forked from acouzens/open5gs
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:
parent
0ec0b2dc69
commit
f137d1947f
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue