mirror of
				https://github.com/open5gs/open5gs.git
				synced 2025-11-03 21:43:25 +00:00 
			
		
		
		
	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:
		@@ -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);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user