Last Modification for releasing v2.0.19

1. SCTP event size workaround - stolen code from libosmo-netif
2. Remove PFCP User Plane IP resource information
3. Fix the bug when building Initial Context Setup Request with EMM NAS message.
This commit is contained in:
Sukchan Lee 2020-10-31 00:30:42 -04:00
parent 0ec0b2dc69
commit f137d1947f
3 changed files with 145 additions and 24 deletions

View File

@ -153,18 +153,20 @@ ogs_pkbuf_t *ogs_pfcp_up_build_association_setup_request(uint8_t type)
req->up_function_features.data = &ogs_pfcp_self()->up_function_features;
req->up_function_features.len = ogs_pfcp_self()->up_function_features_len;
i = 0;
ogs_list_for_each(&ogs_pfcp_self()->gtpu_resource_list, resource) {
ogs_assert(i < OGS_MAX_NUM_OF_GTPU_RESOURCE);
ogs_pfcp_tlv_user_plane_ip_resource_information_t *message =
&req->user_plane_ip_resource_information[i];
ogs_assert(message);
if (ogs_pfcp_self()->up_function_features.ftup == 0) {
i = 0;
ogs_list_for_each(&ogs_pfcp_self()->gtpu_resource_list, resource) {
ogs_assert(i < OGS_MAX_NUM_OF_GTPU_RESOURCE);
ogs_pfcp_tlv_user_plane_ip_resource_information_t *message =
&req->user_plane_ip_resource_information[i];
ogs_assert(message);
message->presence = 1;
ogs_pfcp_build_user_plane_ip_resource_info(
message, &resource->info, infobuf[i],
OGS_PFCP_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN);
i++;
message->presence = 1;
ogs_pfcp_build_user_plane_ip_resource_info(
message, &resource->info, infobuf[i],
OGS_PFCP_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN);
i++;
}
}
pfcp_message.h.type = type;
@ -209,18 +211,20 @@ ogs_pkbuf_t *ogs_pfcp_up_build_association_setup_response(uint8_t type,
rsp->up_function_features.data = &ogs_pfcp_self()->up_function_features;
rsp->up_function_features.len = ogs_pfcp_self()->up_function_features_len;
i = 0;
ogs_list_for_each(&ogs_pfcp_self()->gtpu_resource_list, resource) {
ogs_assert(i < OGS_MAX_NUM_OF_GTPU_RESOURCE);
ogs_pfcp_tlv_user_plane_ip_resource_information_t *message =
&rsp->user_plane_ip_resource_information[i];
ogs_assert(message);
if (ogs_pfcp_self()->up_function_features.ftup == 0) {
i = 0;
ogs_list_for_each(&ogs_pfcp_self()->gtpu_resource_list, resource) {
ogs_assert(i < OGS_MAX_NUM_OF_GTPU_RESOURCE);
ogs_pfcp_tlv_user_plane_ip_resource_information_t *message =
&rsp->user_plane_ip_resource_information[i];
ogs_assert(message);
message->presence = 1;
ogs_pfcp_build_user_plane_ip_resource_info(
message, &resource->info, infobuf[i],
OGS_PFCP_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN);
i++;
message->presence = 1;
ogs_pfcp_build_user_plane_ip_resource_info(
message, &resource->info, infobuf[i],
OGS_PFCP_MAX_USER_PLANE_IP_RESOURCE_INFO_LEN);
i++;
}
}
pfcp_message.h.type = type;

View File

@ -244,6 +244,113 @@ int ogs_sctp_recvmsg(ogs_sock_t *sock, void *msg, size_t len,
return size;
}
/* is any of the bytes from offset .. u8_size in 'u8' non-zero? return offset
* or -1 if all zero */
static int byte_nonzero(
const uint8_t *u8, unsigned int offset, unsigned int u8_size)
{
int j;
for (j = offset; j < u8_size; j++) {
if (u8[j] != 0)
return j;
}
return OGS_ERROR;
}
static int sctp_sockopt_event_subscribe_size = 0;
static int determine_sctp_sockopt_event_subscribe_size(void)
{
uint8_t buf[256];
socklen_t buf_len = sizeof(buf);
int sd, rc;
/* only do this once */
if (sctp_sockopt_event_subscribe_size != 0)
return 0;
sd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);
if (sd < 0)
return sd;
rc = getsockopt(sd, IPPROTO_SCTP, SCTP_EVENTS, buf, &buf_len);
ogs_closesocket(sd);
if (rc < 0)
return rc;
sctp_sockopt_event_subscribe_size = buf_len;
ogs_debug("sizes of 'struct sctp_event_subscribe': "
"compile-time %zu, kernel: %u",
sizeof(struct sctp_event_subscribe),
sctp_sockopt_event_subscribe_size);
return 0;
}
/*
* The workaround is stolen from libosmo-netif.
* - http://osmocom.org/projects/libosmo-netif/repository/revisions/master/entry/src/stream.c
*
* Attempt to work around Linux kernel ABI breakage
*
* The Linux kernel ABI for the SCTP_EVENTS socket option has been broken
* repeatedly.
* - until commit 35ea82d611da59f8bea44a37996b3b11bb1d3fd7 ( kernel < 4.11),
* the size is 10 bytes
* - in 4.11 it is 11 bytes
* - in 4.12 .. 5.4 it is 13 bytes
* - in kernels >= 5.5 it is 14 bytes
*
* This wouldn't be a problem if the kernel didn't have a "stupid" assumption
* that the structure size passed by userspace will match 1:1 the length
* of the structure at kernel compile time. In an ideal world, it would just
* use the known first bytes and assume the remainder is all zero.
* But as it doesn't do that, let's try to work around this */
static int sctp_setsockopt_events_linux_workaround(
int fd, const struct sctp_event_subscribe *event)
{
const unsigned int compiletime_size = sizeof(*event);
int rc;
if (determine_sctp_sockopt_event_subscribe_size() < 0) {
ogs_error("Cannot determine SCTP_EVENTS socket option size");
return OGS_ERROR;
}
if (compiletime_size == sctp_sockopt_event_subscribe_size) {
/* no kernel workaround needed */
return setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS,
event, compiletime_size);
} else if (compiletime_size < sctp_sockopt_event_subscribe_size) {
/* we are using an older userspace with a more modern kernel
* and hence need to pad the data */
uint8_t buf[sctp_sockopt_event_subscribe_size];
memcpy(buf, event, compiletime_size);
memset(buf + sizeof(*event),
0, sctp_sockopt_event_subscribe_size - compiletime_size);
return setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS,
buf, sctp_sockopt_event_subscribe_size);
} else /* if (compiletime_size > sctp_sockopt_event_subscribe_size) */ {
/* we are using a newer userspace with an older kernel and hence
* need to truncate the data - but only if the caller didn't try
* to enable any of the events of the truncated portion */
rc = byte_nonzero((const uint8_t *)event,
sctp_sockopt_event_subscribe_size, compiletime_size);
if (rc >= 0) {
ogs_error("Kernel only supports sctp_event_subscribe of %u bytes, "
"but caller tried to enable more modern event at offset %u",
sctp_sockopt_event_subscribe_size, rc);
return OGS_ERROR;
}
return setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, event,
sctp_sockopt_event_subscribe_size);
}
}
static int subscribe_to_events(ogs_sock_t *sock)
{
struct sctp_event_subscribe event;
@ -256,12 +363,19 @@ static int subscribe_to_events(ogs_sock_t *sock)
event.sctp_send_failure_event = 1;
event.sctp_shutdown_event = 1;
#ifdef DISABLE_SCTP_EVENT_WORKAROUND
if (setsockopt(sock->fd, IPPROTO_SCTP, SCTP_EVENTS,
&event, sizeof(event)) != 0) {
ogs_log_message(OGS_LOG_ERROR, ogs_socket_errno,
"Unable to subscribe to SCTP events");
return OGS_ERROR;
}
#else
if (sctp_setsockopt_events_linux_workaround(sock->fd, &event) < 0) {
ogs_error("couldn't activate SCTP events on FD %u", sock->fd);
return OGS_ERROR;
}
#endif
return OGS_OK;
}

View File

@ -424,13 +424,16 @@ ogs_pkbuf_t *s1ap_build_initial_context_setup_request(
bearer->sgw_s1u_teid, &e_rab->gTP_TEID);
if (emmbuf && emmbuf->len) {
nasPdu = (S1AP_NAS_PDU_t *)CALLOC(
1, sizeof(S1AP_NAS_PDU_t));
nasPdu = (S1AP_NAS_PDU_t *)CALLOC(1, sizeof(S1AP_NAS_PDU_t));
nasPdu->size = emmbuf->len;
nasPdu->buf = CALLOC(nasPdu->size, sizeof(uint8_t));
memcpy(nasPdu->buf, emmbuf->data, nasPdu->size);
e_rab->nAS_PDU = nasPdu;
ogs_pkbuf_free(emmbuf);
/* Since Tracking area update accept is used only once,
* set emmbuf to NULL as shown below */
emmbuf = NULL;
}
bearer = mme_bearer_next(bearer);