FreeCalypso > hg > fc-tourmaline
view src/g23m-fad/ip/ip_kerf.c @ 244:96784b8974eb
Switch_ON(): detect charging mode by CHGPRES bit
Consider the following scenario: the phone is on, the user plugs in
the charger, and then executes the power-off operation. In the Iota
VRPC this sequence translates to a switch-off immediately followed
by another switch-on - but the CHGSTS bit doesn't get set on the second
switch-on cycle! Disassembly of Pirelli's fw shows that they check
the CHGPRES bit, and furthermore, if both CHGPRES and ONBSTS are set,
the code they pass to their modified Power_ON_Button() function is
the one for charging - so let's adopt the same CHGPRES check and
the same priority order for switch-on causes.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 03 May 2021 06:51:29 +0000 |
parents | fa8dc04885d8 |
children |
line wrap: on
line source
/* +---------------------------------------------------------------------------- | Project : | Modul : +---------------------------------------------------------------------------- | Copyright 2002 Texas Instruments Berlin, AG | All rights reserved. | | This file is confidential and a trade secret of Texas | Instruments Berlin, AG | The receipt of or possession of this file does not convey | any rights to reproduce or disclose its contents or to | manufacture, use, or sell anything it may describe, in | whole, or in part, without the specific written consent of | Texas Instruments Berlin, AG. +---------------------------------------------------------------------------- | Purpose : This Modul defines the functions for processing | of incomming primitives for the component | Internet Protocol of the mobile station +---------------------------------------------------------------------------- */ #define ENTITY_IP /*==== INCLUDES ===================================================*/ #include <string.h> #include "typedefs.h" #include "pconst.cdg" #include "vsi.h" #include "macdef.h" /* Get PFREE_DESC2 */ #include "pconst.cdg" #include "custom.h" #include "gsm.h" #include "cnf_ip.h" #include "mon_ip.h" #include "prim.h" #include "pei.h" #include "tok.h" #include "ccdapi.h" #include "dti.h" #include "ip.h" #include "ip_udp.h" /* +--------------------------------------------------------------------+ | PROJECT : WAP MODULE : ip_kerf.c | | STATE : code ROUTINE : ip_packet_validator | +--------------------------------------------------------------------+ PURPOSE : Checks for IP packet validity */ BOOL ip_packet_validator (T_desc_list2 * desc_list) { TRACE_FUNCTION ("ip_packet_validator()"); if (desc_list == NULL) { TRACE_ERROR ("desc_list == NULL in IP validator."); return FALSE; } { /* Loop once through all the list */ register T_desc2 * desc = (T_desc2 *) desc_list->first; register unsigned length = 0; while (desc != NULL) { /* Check consistency of descs */ if (desc->size < desc->offset + desc->len) { TRACE_ERROR ( "Packet dropped: " "desc->size < desc->offset + desc->len in IP validator." ); return FALSE; /* This is a mistake. Must be DTI1. */ /* desc->offset = 0; */ /* desc->size = desc->len; */ } /* Make sure that all offsets are 0 */ if (desc->offset != 0) { memmove (desc->buffer, desc->buffer + desc->offset, desc->len); desc->offset = 0; } /* Calculate the sum of lengths */ length += desc->len; desc = (T_desc2 *) desc->next; } /* Check desc_list->list_len */ if (desc_list->list_len != length) { TRACE_ERROR ( "Packet dropped: " "desc_list->list_len != length in IP validator." ); return FALSE; /* This is a mistake. But we could live with it. */ /* desc_list->list_len = (USHORT) length; */ } /* Need at least LEN_IP_HEADER_B bytes for one header */ if (length < LEN_IP_HEADER_B) { TRACE_ERROR ( "Packet dropped: " "length < LEN_IP_HEADER_B in IP validator." ); return FALSE; } /* Have enough bytes, but they may be distributed */ desc = (T_desc2 *) desc_list->first; if (desc->len < LEN_IP_HEADER_B) { /* Collect all bytes in one desc */ T_desc2 * bigdesc = M_ALLOC (offsetof (T_desc2, buffer) + length); if (bigdesc == NULL) { TRACE_ERROR ("Not enough memory in IP validator."); return FALSE; } bigdesc->next = 0; bigdesc->offset = 0; bigdesc->len = (USHORT) length; bigdesc->size = (USHORT) length; /* Loop again through all the list */ length = 0; while (desc != NULL) { T_desc2 * removable = desc; memcpy (bigdesc->buffer + length, desc->buffer, desc->len); length += desc->len; desc = (T_desc2 *) desc->next; MFREE (removable); } desc_list->first = (ULONG) bigdesc; desc = bigdesc; } /* Need at least GET_IP_HEADER_LEN_B() bytes for the IP header */ if (length < (unsigned) GET_IP_HEADER_LEN_B (desc->buffer)) { TRACE_ERROR ( "Packet dropped: " "length < GET_IP_HEADER_LEN_B() in IP validator." ); return FALSE; } /* Survived */ return TRUE; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-FaD (8444) MODULE : IP_KERF | | STATE : code ROUTINE : free_primitive_data_ind | +--------------------------------------------------------------------+ * * Set a DTI_DATA_IND primitive free and the pointer to NULL */ void free_primitive_data_ind (T_DTI2_DATA_IND ** dti_data_ind) { TRACE_FUNCTION ("free_primitive_data_ind()"); if (dti_data_ind != NULL && *dti_data_ind != NULL) { PFREE_DESC2 (* dti_data_ind); *dti_data_ind = NULL; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-FaD (8444) MODULE : IP_KERF | | STATE : code ROUTINE : free_primitive_data_req | +--------------------------------------------------------------------+ * * Set a DTI_DATA_REQ primitive free and the pointer to NULL */ void free_primitive_data_req (T_DTI2_DATA_REQ ** dti_data_req) { TRACE_FUNCTION ("free_primitive_data_req()"); if (dti_data_req != NULL && *dti_data_req != NULL) { PFREE_DESC2 (* dti_data_req); *dti_data_req = NULL; } } /* +--------------------------------------------------------------------+ | PROJECT : WAP MODULE : IP | | STATE : code ROUTINE : set_desc_len | +--------------------------------------------------------------------+ * * Set the new desc length and fix desc_list length */ void set_desc_len (T_desc_list2 * desc_list, T_desc2 * desc, USHORT len_desc) { TRACE_FUNCTION ("set_desc_len()"); desc_list->list_len = (USHORT) (desc_list->list_len + len_desc - desc->len); desc->len = len_desc; } /* +--------------------------------------------------------------------+ | PROJECT : WAP MODULE : IP | | STATE : code ROUTINE : del_rest_descs | +--------------------------------------------------------------------+ * * Free the next desc(s) from desc. Fix the list_len in desc_list */ void del_rest_descs (T_desc_list2 * desc_list, T_desc2 * desc) { BOOL go = TRUE; T_desc2 * p_desc_last, * p_desc_start; TRACE_FUNCTION ("del_rest_descs()"); if (desc->next > 0) { p_desc_start = desc; desc = (T_desc2 *) desc->next; do { p_desc_last = desc; if (desc->next > 0) desc = (T_desc2 *) desc->next; else go = FALSE; desc_list->list_len = (USHORT) (desc_list->list_len - p_desc_last->len); MFREE (p_desc_last); } while (go); desc = p_desc_start; desc->next = 0; } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-FaD (8444) MODULE : IP_KERF | | STATE : code ROUTINE : del_descs | +--------------------------------------------------------------------+ * * Free the desc(s) */ void del_descs (T_desc2 * desc) { BOOL go = TRUE; T_desc2 * p_desc_last; TRACE_FUNCTION ("del_descs()"); do { p_desc_last = desc; if (desc->next > 0) desc = (T_desc2 *) desc->next; else go = FALSE; MFREE (p_desc_last); } while (go); } /** filter_out_in_desc * * cuts length bytes out of a T_desc2::buffer, starting at 'start'. * * @param desc Pointer to a T_desc2 * @param start Start of the block to be cut out * @param length Length of the block to be cut out * * @return TRUE if parameters are valid, FALSE if parameters are invalid */ static BOOL filter_out_in_desc ( T_desc2 * desc, USHORT start, USHORT length ) { TRACE_FUNCTION ("filter_out_in_desc()"); if (desc != NULL && start + length <= desc->len) { memmove ( desc->buffer + start, desc->buffer + start + length, desc->len - start - length ); desc->len = (USHORT) (desc->len - length); return TRUE; } else { TRACE_ERROR ("Parameters are invalid in filter_out_in_desc()."); return FALSE; } } /** truncate_descs * * truncates a T_desc_list2 to no more than new_length bytes. * * @param desc_list Pointer to a T_desc_list2 * @param new_length Maximal new length of that T_desc_list2 */ void truncate_descs (T_desc_list2 * desc_list, USHORT new_length) { TRACE_FUNCTION ("truncate_descs()"); if (desc_list != NULL) { T_desc2 ** pp_desc = (T_desc2 **) & desc_list->first; desc_list->list_len = 0; /* Will be recalculated, anyway */ /* First a loop over all T_descs which will remain. */ while (*pp_desc != NULL && new_length != 0) { if (new_length < (*pp_desc)->len) (*pp_desc)->len = new_length; new_length = (USHORT) (new_length - (*pp_desc)->len); desc_list->list_len = /* Recalculation */ (USHORT) (desc_list->list_len + (*pp_desc)->len); pp_desc = (T_desc2 **) & (*pp_desc)->next; } /* Second a loop over all T_descs which have to be deleted, if any. */ while (*pp_desc != NULL) { T_desc2 * p_desc_removable = *pp_desc; *pp_desc = (T_desc2 *) p_desc_removable->next; MFREE (p_desc_removable); } /* This way, new_length==0 at function call results in * desc_list->first==NULL at function return. */ /* Third a loop over all T_descs which have to be created, if any. * (If it were Prokrustes, not truncation, * we would have to allocate new T_descs here.) * while (new_length != 0) { ... } */ } else { TRACE_ERROR ("truncate_descs() called without T_desc_list2."); TRACE_ASSERT (0); } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-FaD (8444) MODULE : IP_KERF | | STATE : code ROUTINE : insert_sort_descs | +--------------------------------------------------------------------+ * * Insert a new descriptor sorted by fragment offset. * The less value at first. Filter out descs with same offset. */ static void insert_sort_desc (T_desc_list2 * desc_list, T_desc2 * p_new_desc) { if (desc_list != NULL && p_new_desc != NULL) { T_desc2 * desc; T_desc2 * p_desc_last; UBYTE * ip_header; USHORT offset, new_offset; offset = 0xffff; ip_header = p_new_desc->buffer; new_offset = (USHORT) GET_IP_FRAG_OFFSET (ip_header);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */ desc = (T_desc2 *) desc_list->first; p_desc_last = NULL; while (desc NEQ NULL) { ip_header = desc->buffer; offset = (USHORT) GET_IP_FRAG_OFFSET (ip_header);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */ if (new_offset <= offset) break; p_desc_last = desc; desc = (T_desc2 *) desc->next; } if (new_offset EQ offset) { /* Two descriptors with the same offset * Throw away the new one */ MFREE (p_new_desc); } else { /* Insert descriptor after p_desc_last */ if (p_desc_last EQ NULL) { p_new_desc->next = desc_list->first; desc_list->first = (ULONG) p_new_desc; } else { p_new_desc->next = p_desc_last->next; p_desc_last->next = (ULONG) p_new_desc; } /* Add the length of the new descriptor */ desc_list->list_len = (USHORT) (desc_list->list_len + p_new_desc->len); } } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-FaD (8444) MODULE : IP_KERF | | STATE : code ROUTINE : reassemble_fragments | +--------------------------------------------------------------------+ * * Reassemble fragments coming in downlink */ void reassemble_fragments ( T_DTI2_DATA_IND ** dti_data_ind, T_LOLA * p_dl, UBYTE * ip_header, BOOL first_segment, /* BOOL middle_segment, */ BOOL last_segment /*,*/ /* USHORT fragm_offset */ ) { USHORT fragm_id, header_len_b, offset; UBYTE fragm_prot; ULONG server_source_addr; BOOL found_source_addr = FALSE; TRACE_FUNCTION ("reassemble_fragments()"); fragm_id = (USHORT) GET_IP_IDENT (ip_header); fragm_prot = GET_IP_PROT (ip_header); server_source_addr = GET_IP_SOURCE_ADDR (ip_header); /* Check source address from server */ p_dl->pos_server = 0; do { if (p_dl->ip_source_addr_segment[p_dl->pos_server] NEQ server_source_addr) p_dl->pos_server++; else found_source_addr = TRUE; } while (! found_source_addr && p_dl->pos_server < MAX_SEGM_SERVER); /* Select the server - by only one server p_dl->pos_server = 0 */ if (p_dl->pos_server EQ MAX_SEGM_SERVER) p_dl->pos_server = 0; p_dl->ip_source_addr_segment[p_dl->pos_server] = server_source_addr; /* Check if it is the first or the last segment */ if (first_segment) p_dl->got_first_segment[p_dl->pos_server] = TRUE; if (last_segment) p_dl->got_last_segment[p_dl->pos_server] = TRUE; /* Is it the first of any segment type? */ if (p_dl->state_reassembly[p_dl->pos_server] EQ NO_SEGMENTS) { p_dl->data_ind_reassembly[p_dl->pos_server] = *dti_data_ind; p_dl->state_reassembly[p_dl->pos_server] = READ_SEGMENT; p_dl->id_reassemble[p_dl->pos_server] = fragm_id; p_dl->prot_reassemble[p_dl->pos_server] = fragm_prot; /* Start reassembly timer */ /* Implementation problem: the timer index must be * layer * MAX_SEGM_SERVER + p_dl->pos_server. The * layer variable is not forwarded to the function. * It works, because layer is ever set to 0 in the moment. */ vsi_t_start (VSI_CALLER p_dl->pos_server, TIME_REASSEMBLY); p_dl->timer_reass_running[p_dl->pos_server] = TRUE; } /* Check the fragment ID and protocol. If not the same - free resources */ else if ( (p_dl->id_reassemble[p_dl->pos_server] NEQ fragm_id) OR (p_dl->prot_reassemble[p_dl->pos_server] NEQ fragm_prot) ) { if (p_dl->timer_reass_running[p_dl->pos_server]) { /* Implementation problem: the timer index must be * layer * MAX_SEGM_SERVER + p_dl->pos_server. The * layer variable is not forwarded to the function. * It works, because layer is ever set to 0 in the moment. */ csf_stop_timer (p_dl->pos_server); p_dl->timer_reass_running[p_dl->pos_server] = FALSE; } p_dl->drop_packet = TRUE; p_dl->state_reassembly[p_dl->pos_server] = NO_SEGMENTS; free_primitive_data_ind (p_dl->data_ind_reassembly + p_dl->pos_server); /* Note: We could generate an ICMP packet */ return; } else /* Got correct segments before */ { /* Note: The whole datagram must be in the same descriptor */ /* Note: The timeout value should be changed to MAX (TTL, TIME_REASSEMBLY) */ BOOL all_fragments_received = FALSE; T_desc_list2 * desc_list = & p_dl->data_ind_reassembly[p_dl->pos_server]->desc_list2; T_desc2 * desc = (T_desc2 *) p_dl->dti_data_ind->desc_list2.first; if (desc == NULL || (T_desc2 *) desc_list->first == NULL) { TRACE_ERROR ("Pointer is NULL."); return; } /* Insert the descriptor in the right position, according to the offset */ insert_sort_desc (desc_list, desc); /* Check if got all fragments */ if ( p_dl->got_first_segment[p_dl->pos_server] AND p_dl->got_last_segment[p_dl->pos_server] ) { BOOL go = TRUE; USHORT data_len, next_offset; UBYTE * ip_packet; desc = (T_desc2 *) desc_list->first; ip_packet = desc->buffer; header_len_b = (USHORT) GET_IP_HEADER_LEN_B (ip_packet); data_len = (USHORT) (desc->len - header_len_b); next_offset = 0; do { if ((T_desc2 *) desc->next != NULL) { desc = (T_desc2 *) desc->next; ip_packet = desc->buffer; next_offset = (USHORT) GET_IP_FRAG_OFFSET_B (ip_packet);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */ header_len_b = (USHORT) GET_IP_HEADER_LEN_B (ip_packet); if ((T_desc2 *) desc->next != NULL) data_len = (USHORT) (data_len + desc->len - header_len_b); } else go = FALSE; } while (go); if (data_len >= next_offset) all_fragments_received = TRUE; } /* Reassemble the fragments */ if (all_fragments_received) { BOOL go = TRUE; USHORT len_fragments, header_len_b_first; T_desc2 * p_desc_first, * p_desc_last; UBYTE * ip_packet; p_dl->state_reassembly[p_dl->pos_server] = NO_SEGMENTS; if ( desc_list == NULL || (T_desc2 *) desc_list->first == NULL || (T_desc2 *) ((T_desc2*)desc_list->first)->next == NULL ) { TRACE_ERROR ("Pointer is NULL."); return; } /* Fix the first desc */ p_desc_first = (T_desc2 *) desc_list->first; ip_packet = p_desc_first->buffer; header_len_b_first = (USHORT) GET_IP_HEADER_LEN_B (ip_packet); /* Start from next desc */ desc = (T_desc2 *) p_desc_first->next; ip_packet = desc->buffer; offset = (USHORT) GET_IP_FRAG_OFFSET_B (ip_packet);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */ p_desc_first->len = (USHORT) (offset + header_len_b_first); len_fragments = offset; do { if (desc->next NEQ 0) { p_desc_last = desc; desc = (T_desc2 *) desc->next; /* Get the fragment offset */ ip_packet = desc->buffer; header_len_b = (USHORT) GET_IP_HEADER_LEN_B (ip_packet); offset = (USHORT) GET_IP_FRAG_OFFSET_B (ip_packet);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */ /* Filter out IP header */ ip_packet = p_desc_last->buffer; header_len_b = (USHORT) GET_IP_HEADER_LEN_B (ip_packet); filter_out_in_desc (p_desc_last, 0, header_len_b); len_fragments = (USHORT) (len_fragments + p_desc_last->len); } else { go = FALSE; /* Filter out last IP header */ ip_packet = desc->buffer; header_len_b = (USHORT) GET_IP_HEADER_LEN_B (ip_packet); filter_out_in_desc (desc, 0, header_len_b); len_fragments = (USHORT) (len_fragments + desc->len); } } while (go); /* Build the IP datagram */ /* Implementation problem: the timer index must be * layer * MAX_SEGM_SERVER + p_dl->pos_server. The * layer variable is not forwarded to the function. * It works, because layer is ever set to 0 in the moment. */ csf_stop_timer (p_dl->pos_server); p_dl->timer_reass_running[p_dl->pos_server] = FALSE; /* PFREE (dti_data_ind); */ /* Is being freed elsewhere. Would anyway have false level of indirection. */ p_dl->data_ind_reassembly[p_dl->pos_server]->desc_list2.list_len = (USHORT) (len_fragments + header_len_b_first); *dti_data_ind = p_dl->data_ind_reassembly[p_dl->pos_server]; p_desc_first = (T_desc2 *) (*dti_data_ind)->desc_list2.first; ip_packet = p_desc_first->buffer; { ULONG dest_addr; UBYTE ttl; dest_addr = GET_IP_DEST_ADDR (ip_packet);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */ ttl = GET_IP_TTL (ip_packet);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */ build_ip_header ( ip_packet, fragm_id, (UBYTE) (header_len_b_first >> 2), NORMAL_SERVICE, ttl, p_dl->ip_source_addr_segment[p_dl->pos_server], dest_addr, (UBYTE) (len_fragments + header_len_b_first), NO_OFFSET_FRAG, FLAG_NOT_SET, FLAG_NOT_SET, fragm_prot ); } p_dl->data_ind_reassembly[p_dl->pos_server] = NULL; } /* else */ /* PFREE (dti_data_ind); */ /* Is being freed elsewhere. Would anyway have false level of indirection. */ } } /* +--------------------------------------------------------------------+ | PROJECT : WAP MODULE : IP | | STATE : code ROUTINE : put_desc_first_pos | +--------------------------------------------------------------------+ * * Put desc on the first position of a desc_list. * Set the new list_len in desc_list. */ void put_desc_first_pos (T_desc_list2 * desc_list, T_desc2 * p_desc_new) { ULONG help; T_desc2 * p_desc_help; TRACE_FUNCTION ("put_desc_first_pos()"); p_desc_help = (T_desc2 *) desc_list->first; if (p_desc_help NEQ p_desc_new) { help = desc_list->first; desc_list->first = (ULONG) p_desc_new; p_desc_new->next = help; desc_list->list_len = (USHORT) (desc_list->list_len + p_desc_new->len); } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-FaD (8444) MODULE : IP_KER | | STATE : code ROUTINE : copy_from_descs_to_desc | +--------------------------------------------------------------------+ * * Copy data from one or more descs into desc_new. Possible to use offset. */ void copy_from_descs_to_desc ( T_desc2 ** desc, T_desc2 * desc_new, USHORT copy_len, USHORT offset_desc, USHORT offset_desc_new, USHORT * pos_copy, USHORT * total_len_copy ) { BOOL go = TRUE; *pos_copy = offset_desc; *total_len_copy = 0; do { while ( (*pos_copy < (*desc)->len) AND (offset_desc_new < desc_new->len) AND (*total_len_copy < copy_len) ) { desc_new->buffer[offset_desc_new] = (*desc)->buffer[*pos_copy]; offset_desc_new ++; (*pos_copy)++; (*total_len_copy)++; } if ( (*total_len_copy >= copy_len) OR (offset_desc_new >= desc_new->len) ) { go = FALSE; } else { if (*pos_copy >= (*desc)->len) { if ((*desc)->next > 0) { *desc = (T_desc2 *) (*desc)->next; *pos_copy = 0; } else { go = FALSE; } } } } while (go); } /* +--------------------------------------------------------------------+ | PROJECT : WAP MODULE : IP | | STATE : code ROUTINE : make_new_desc | +--------------------------------------------------------------------+ * * Malloc a new desc. Init buffer 0 if buff_init_0 = TRUE */ BOOL make_new_desc ( T_desc2 ** p_desc_new, USHORT malloc_len, BOOL buff_init_0 ) { TRACE_FUNCTION ("make_new_desc()"); MALLOC (*p_desc_new, offsetof (T_desc2, buffer) + malloc_len); /* The target compiler issues a warning * "pointer type conversion may violate alignment constraints" * here and everywhere where MALLOC is being used. */ if (*p_desc_new EQ 0) return FALSE; if (buff_init_0) { USHORT i; for (i = 0; i < malloc_len; i++) (*p_desc_new)->buffer[i] = 0; } (*p_desc_new)->next = 0; (*p_desc_new)->offset = 0; (*p_desc_new)->len = malloc_len; (*p_desc_new)->size = malloc_len; return TRUE; } #if 0 /* +--------------------------------------------------------------------+ | PROJECT : GSM-FaD (8444) MODULE : IP_KERF | | STATE : code ROUTINE : sort_descs_id_up | +--------------------------------------------------------------------+ * * Sort the descs with fragment offset. The less value at * first. Filter out descs with same offset. */ USHORT sort_descs_id_up ( T_desc_list * desc_list, ULONG sort_array[2][MAX_SEGMENTS] ) { T_desc * desc; USHORT i, n_descs, code; BOOL go = TRUE; ULONG addr, wert; UBYTE * ip_header; TRACE_FUNCTION ("sort_descs_id_up()"); desc = (T_desc *) desc_list->first; n_descs = 0; code = GO_ON_SEGMENTING; if (desc->next > 0) { /* Write desc address and search-value into sort_array */ desc = (T_desc *) desc_list->first; i = 0; ip_header = desc->buffer; sort_array[1][i] = GET_IP_FRAG_OFFSET (ip_header); sort_array[0][i++] = desc_list->first; do { if (desc->next > 0 AND i < MAX_SEGMENTS) { desc = (T_desc *) desc->next; sort_array[0][i] = (ULONG) desc; ip_header = desc->buffer; sort_array[1][i++] = GET_IP_FRAG_OFFSET (ip_header); } else go = FALSE; } while (go); /* Sort the array if not overflow */ if (i < MAX_SEGMENTS) { n_descs = i; for (i = 0; i < n_descs - 1; i++) { USHORT min, j; min = i; for (j = i + 1; j < n_descs; j++) if (sort_array[1][j] < sort_array[1][min]) min = j; addr = sort_array[0][i]; wert = sort_array[1][i]; sort_array[0][i] = sort_array[0][min]; sort_array[1][i] = sort_array[1][min]; sort_array[0][min] = addr; sort_array[1][min] = wert; } /* Filter out descs with same fragment offset */ { ULONG v1; USHORT j, k, len; len = n_descs - 1; i = 0; while (i < len) { v1 = sort_array[1][i]; j = i + 1; if (v1 EQ sort_array[1][j]) { k = j; n_descs--; while (k <= len) { sort_array[0][k] = sort_array[0][k + 1]; sort_array[1][k] = sort_array[1][k + 1]; k++; } len--; } if (sort_array[1][i] NEQ sort_array[1][i + 1]) i++; } } /* Put the descs together and correct the desc_list->list_len */ desc_list->first = sort_array[0][0]; desc = (T_desc *) sort_array[0][0]; desc_list->list_len = 0; desc_list->list_len = desc->len; for (i = 1; i < n_descs; i++) { desc->next = sort_array[0][i]; desc = (T_desc *) desc->next; desc_list->list_len = desc_list->list_len + desc->len; } desc->next = 0; } else code = NO_SPACE_SEGMENTING; desc = (T_desc *) desc_list->first; } return code; } #endif /* +--------------------------------------------------------------------+ | PROJECT : GSM-FaD (8444) MODULE : IP_KERF | | STATE : code ROUTINE : build_ip_header | +--------------------------------------------------------------------+ * * Build IP header */ void build_ip_header ( UBYTE * ip_header_new, USHORT identity, UBYTE header_len, UBYTE type_of_service, UBYTE ttl, ULONG src_addr, ULONG dest_addr, USHORT total_len, USHORT fragm_offset, UBYTE df_flag, UBYTE mf_flag, UBYTE prot ) { USHORT chk_sum; TRACE_FUNCTION ("build_ip_header()"); SET_IP_VERSION (ip_header_new, IP_VERSION); /*lint -e{415, 416} (Warning -- access/creation of out-of-bounds pointer) */ { SET_IP_HEADER_LEN (ip_header_new, header_len); SET_IP_TYPE_OF_SERVICE (ip_header_new, type_of_service); SET_IP_TOTAL_LEN (ip_header_new, total_len); SET_IP_IDENT (ip_header_new, identity); SET_IP_OFF_FLAG (ip_header_new, FLAG_NOT_SET); SET_IP_DF_FLAG (ip_header_new, df_flag); SET_IP_MF_FLAG (ip_header_new, mf_flag); SET_IP_FRAG_OFFSET (ip_header_new, fragm_offset); SET_IP_PROT (ip_header_new, prot); SET_IP_TTL (ip_header_new, ttl); SET_IP_SOURCE_ADDR (ip_header_new, src_addr); SET_IP_DEST_ADDR (ip_header_new, dest_addr); RESET_IP_CHECKSUM (ip_header_new); chk_sum = inet_checksum (ip_header_new, (USHORT) (header_len * 4)); SET_IP_CHECKSUM (ip_header_new, chk_sum); } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-FaD (8444) MODULE : IP_KERF | | STATE : code ROUTINE : build_icmp_packet | +--------------------------------------------------------------------+ * * Build IP icmp packet without payload */ void build_icmp_packet ( USHORT header_len_b, UBYTE typ, UBYTE code, UBYTE ttl, UBYTE * ip_header, USHORT identity, ULONG dest_addr, ULONG src_addr, T_desc_list2 * desc_list ) { USHORT chk_sum; UBYTE header_len_b_bak; TRACE_FUNCTION ("build_icmp_packet()"); header_len_b_bak = (UBYTE) (header_len_b >> 2); /* Build ICMP header */ SET_ICMP_TYPE (ip_header, typ, header_len_b); SET_ICMP_CODE (ip_header, code, header_len_b); RESET_ICMP_CHK_SUM (ip_header, header_len_b); chk_sum = desc_checksum (desc_list, header_len_b, 0); SET_ICMP_CHK_SUM (ip_header, chk_sum, header_len_b); /* Build IP header */ build_ip_header ( ip_header, identity, header_len_b_bak, NORMAL_SERVICE, ttl, src_addr, dest_addr, desc_list->list_len, NO_OFFSET_FRAG, FLAG_NOT_SET, FLAG_NOT_SET, ICMP_PROT ); } /* +-------------------------------------------------------------------+ | PROJECT : WAP MODULE : IP | | STATE : code ROUTINE : build_icmp_with_payload | +-------------------------------------------------------------------+ * * Build a ICMP packet with payload of 64 bits */ void build_icmp_with_payload ( T_DTI2_DATA_REQ * data_req, USHORT identity, UBYTE ttl, ULONG src_addr, UBYTE icmp_type, UBYTE icmp_code ) { T_desc2 * desc_new, * desc; T_desc_list2 * desc_list; USHORT malloc_len, header_len_b, chk_sum; UBYTE * ip_header; ULONG dest_addr; #define LEN_ICMP_HEADER_PAYLOAD 8 #define LEN_PAYLOAD 8 TRACE_FUNCTION ("build_icmp_with_payload()"); desc_list = & data_req->desc_list2; desc = (T_desc2 *) desc_list->first; ip_header = desc->buffer; dest_addr = GET_IP_SOURCE_ADDR (ip_header);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */ header_len_b = (USHORT) GET_IP_HEADER_LEN_B (ip_header); /* Up to 8 bytes payload of the old datagram */ { USHORT help = (USHORT) (LEN_PAYLOAD + header_len_b); if (help < desc->len) set_desc_len (desc_list, desc, help); } /* Throw away the rest descs if there are any */ del_rest_descs (desc_list, desc); /* Make a new desc for the ICMP packet header */ malloc_len = LEN_ICMP_HEADER_PAYLOAD + LEN_IP_HEADER_B; make_new_desc (& desc_new, malloc_len, TRUE); /* Put the desc at the first place of the descs */ put_desc_first_pos (desc_list, desc_new); /* Build the ICMP packet and the IP header */ ip_header = desc_new->buffer; header_len_b = LEN_IP_HEADER_B; SET_ICMP_TYPE (ip_header, icmp_type, header_len_b);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */ SET_ICMP_CODE (ip_header, icmp_code, header_len_b);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */ RESET_ICMP_CHK_SUM (ip_header, header_len_b);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */ chk_sum = desc_checksum (desc_list, header_len_b, 0); SET_ICMP_CHK_SUM (ip_header, chk_sum, header_len_b);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */ build_ip_header ( ip_header, identity, MIN_HEADER_LEN, NORMAL_SERVICE, ttl, src_addr, dest_addr, desc_list->list_len, NO_OFFSET_FRAG, FLAG_NOT_SET, FLAG_NOT_SET, ICMP_PROT ); } /* +--------------------------------------------------------------------+ | PROJECT : WAP MODULE : IP_KERF | | STATE : code ROUTINE : init_ip | +--------------------------------------------------------------------+ * * Init the global parameter */ void init_ip (void) { T_HILA * p_ul = & ip_data->hila; T_LOLA * p_dl = & ip_data->lola; T_KER * p_ker = & ip_data->ker; USHORT j; INIT_STATE (HILA, DOWN); INIT_STATE (LOLA, DOWN); INIT_STATE (KER, DEACTIVATED); p_ul->dti_data_req = NULL; p_ul->drop_packet = FALSE; p_ul->ttl = STANDARD_TTL; p_ul->header_len = MIN_HEADER_LEN; p_ul->state_segment = NO_SEGMENTS; p_ul->segment_offset = 0; p_ul->segment_prot = NO_PROT_ID; p_ul->first_desc_segment = NULL; p_ul->identity = IDENTITY_0; p_dl->drop_packet = FALSE; p_dl->dti_data_ind= NULL; p_dl->pos_server = 0; for (j = 0; j < MAX_SEGM_SERVER; j++) { p_dl->state_reassembly[j] = NO_SEGMENTS; p_dl->got_first_segment[j] = FALSE; p_dl->got_last_segment[j] = FALSE; p_dl->ip_source_addr_segment[j] = NO_ADDR; p_dl->data_ind_reassembly[j] = NULL; p_dl->id_reassemble[j] = NO_ID_REASSBL; p_dl->prot_reassemble[j] = NO_PROT_REASSBL; } p_ker->peer_addr = NO_ADDR; p_ker->netmask = INIT_NETMASK; p_ker->source_addr = NO_ADDR; p_ker->dst_addr = NO_ADDR; #ifdef _SIMULATION_ p_ker->source_addr = TEST_SRC_ADDR; p_ker->dst_addr = TEST_DEST_ADDR; #endif p_ker->entity_name_hl[0] = 0; p_ker->entity_name_ll[0] = 0; p_ker->link_id_ll = IPA_LINK_ID_DEFAULT; p_ker->link_id_hl = IPA_LINK_ID_DEFAULT; p_ker->mtu = NO_MTU; p_ker->icmp_dti_data_req = NULL; p_ker->send_icmp = FALSE; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-FaD (8444) MODULE : IP_KERF | | STATE : code ROUTINE : config_down_ll | +--------------------------------------------------------------------+ * * Config down a lower layer entity */ void config_down_ll (void) { T_HILA * p_ul = & ip_data->hila; T_LOLA * p_dl = & ip_data->lola; T_KER * p_ker = & ip_data->ker; USHORT j; TRACE_FUNCTION ("config_down_ll()"); free_primitive_data_ind (& p_dl->dti_data_ind); free_primitive_data_req (& p_ker->icmp_dti_data_req); for (j = 0; j < MAX_SEGM_SERVER; j++) { /* free_primitive_data_ind (p_dl->data_ind_reassembly + j); */ /* Has already been freed five lines above, */ /* because p_dl->dti_data_ind == p_dl->data_ind_reassembly. */ /* Please think anew when MAX_SEGM_SERVER becomes != 1. */ csf_stop_timer (j); p_dl->timer_reass_running[j] = FALSE; p_dl->state_reassembly[j] = NO_SEGMENTS; p_dl->got_first_segment[j] = FALSE; p_dl->got_last_segment[j] = FALSE; p_dl->ip_source_addr_segment[j] = NO_ADDR; p_dl->data_ind_reassembly[j] = NULL; p_dl->id_reassemble[j] = NO_ID_REASSBL; p_dl->prot_reassemble[j] = NO_PROT_REASSBL; } /* Keep STATE_WAIT are stored even if config down * send READY_IND and set HILA STATE to IDLE if */ switch (GET_STATE (HILA)) { case WAIT: /* Keep state */ break; case SEND: /* Send ready indication */ dti_start ( ip_hDTI, IP_DTI_DEF_INSTANCE, IP_DTI_HL_INTERFACE, IP_DTI_DEF_CHANNEL ); default: SET_STATE (HILA, IDLE); break; } SET_STATE (HILA, IDLE) p_ul->drop_packet = FALSE; p_ul->state_segment = NO_SEGMENTS; p_ul->header_len = MIN_HEADER_LEN; p_ul->ttl = STANDARD_TTL; p_ul->segment_prot = NO_PROT_ID; p_ul->segment_offset = 0; p_ul->first_desc_segment = NULL; /* Be sure that STATE_WAIT are stored even if config down */ if (GET_STATE (LOLA) NEQ WAIT) SET_STATE (LOLA, IDLE) p_dl->drop_packet = FALSE; p_dl->pos_server = 0; p_ker->peer_addr = NO_ADDR; p_ker->netmask = INIT_NETMASK; p_ker->source_addr = NO_ADDR; p_ker->dst_addr = NO_ADDR; p_ker->entity_name_ll[0] = 0; p_ker->mtu = NO_MTU; p_ker->send_icmp = FALSE; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-FaD (8444) MODULE : IP_KERF | | Sp_TATE : code ROUTINE : terminate_ip | +--------------------------------------------------------------------+ * * Handle global parameter by terminate */ void terminate_ip (void) { TRACE_FUNCTION ("terminate_ip()"); /* Shutdown lower entity interface */ config_down_ll (); /* Parameter for higher layer entity */ ip_data->ker.entity_name_hl[0] = 0; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-FaD (8444) MODULE : IP_KERF | | STATE : code ROUTINE : ip_addr_int_to_byte | +--------------------------------------------------------------------+ * * Build the IP address in ULONG to 4 bytes */ void ip_addr_int_to_byte (UBYTE * b_values, ULONG ul_value) { TRACE_FUNCTION ("int_to_byte()"); b_values[3] = (UBYTE) (ul_value); b_values[2] = (UBYTE) (ul_value>>8); b_values[1] = (UBYTE) (ul_value>>16); b_values[0] = (UBYTE) (ul_value>>24); } /* +--------------------------------------------------------------------+ | PROJECT : GSM-FaD (8444) MODULE : IP_KERF | | STATE : code ROUTINE : chk_packet_len | +--------------------------------------------------------------------+ * * Check the IP packet length */ UBYTE chk_packet_len (UBYTE * ip_header, T_desc_list2 * desc_list) { USHORT total_len, chk_len, mtu_len; TRACE_FUNCTION ("chk_packet_len()"); /* This is the calculated length */ total_len = desc_list->list_len; /* This is the length indicated in the IP header */ chk_len = (USHORT) GET_IP_TOTAL_LEN (ip_header); /* This is the max defined packet length */ mtu_len = ip_data->ker.mtu; if ( (chk_len < MIN_HEADER_LEN) OR (chk_len > total_len) OR (total_len < MIN_HEADER_LEN) OR (chk_len > mtu_len) ) return ERR_PACKET_LEN; else if (chk_len < total_len) return CHANGE_PACKET_LEN; else return NO_ERROR; } /* +--------------------------------------------------------------------+ | PROJECT : GSM-FaD (8444) MODULE : IP_KERF | | STATE : code ROUTINE : build_ip_packet | +--------------------------------------------------------------------+ * * Build the datagram or packets before sending */ void build_ip_packet (BOOL uplink, UBYTE select) { UBYTE * ip_header; USHORT total_len; ULONG dest_addr, src_addr; T_desc_list2 * desc_list; T_desc2 * desc; T_HILA * p_ul = & ip_data->hila; T_LOLA * p_dl = & ip_data->lola; T_KER * p_ker = & ip_data->ker; T_DTI2_DATA_REQ * data_req; T_DTI2_DATA_IND * data_ind; TRACE_FUNCTION ("build_ip_packet()"); src_addr = p_ker->source_addr; /* Build uplink packets */ if (uplink) { data_req = p_ul->dti_data_req; switch (select) { /* Build "standard" IP packet */ case B_NORMAL_PACKET: desc_list = & p_ul->dti_data_req->desc_list2; total_len = desc_list->list_len; desc = (T_desc2 *) desc_list->first; ip_header = desc->buffer; dest_addr = GET_IP_DEST_ADDR (ip_header);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */ build_ip_header ( ip_header, p_ul->identity, (UBYTE) p_ul->header_len, NORMAL_SERVICE, p_ul->ttl, src_addr, dest_addr, total_len, NO_OFFSET_FRAG, FLAG_NOT_SET, FLAG_NOT_SET, UDP_PROT ); #ifndef _SIMULATION_ p_ul->identity++; #endif break; /* Build IP header for ICMP messages. Note only ICMP from higher layer. */ case B_ICMP_PACKET: desc_list = & p_ul->dti_data_req->desc_list2; total_len = desc_list->list_len; desc = (T_desc2 *) desc_list->first; ip_header = desc->buffer; dest_addr = GET_IP_DEST_ADDR (ip_header);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */ build_ip_header ( ip_header, p_ul->identity, (UBYTE) p_ul->header_len, NORMAL_SERVICE, p_ul->ttl, src_addr, dest_addr, total_len, NO_OFFSET_FRAG, FLAG_NOT_SET, FLAG_NOT_SET, ICMP_PROT ); #ifndef _SIMULATION_ p_ul->identity++; #endif break; /* Build fragments. The first fragment use the original header from HL. */ case B_SEGMENT: { /* Check if it is the first fragment */ if (p_ul->state_segment EQ NO_SEGMENTS) { T_desc2 * desc_new; USHORT pos_copy, total_len_copy, malloc_len, header_len_b; desc_list = & p_ul->dti_data_req->desc_list2; total_len = desc_list->list_len; desc = (T_desc2 *) desc_list->first; ip_header = desc->buffer; dest_addr = GET_IP_DEST_ADDR (ip_header);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */ src_addr = p_ker->source_addr; p_ul->header_len = (USHORT) GET_IP_HEADER_LEN (ip_header); header_len_b = (USHORT) GET_IP_HEADER_LEN_B (ip_header); p_ul->state_segment = SEND_SEGMENT; p_ul->sended_segment_len = p_ker->mtu; p_ul->list_len_segment = total_len; p_ul->segment_prot = GET_IP_PROT (ip_header);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */ p_ul->first_desc_segment = desc; dest_addr = GET_IP_DEST_ADDR (ip_header);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */ /* Make a new desc for the fragment */ malloc_len = p_ker->mtu; make_new_desc (& desc_new, malloc_len, FALSE); data_req->desc_list2.first = (ULONG) desc_new; data_req->desc_list2.list_len = malloc_len; desc_new->next = 0; /* Build the first fragment */ copy_from_descs_to_desc ( & desc, desc_new, malloc_len, 0, 0, & pos_copy, & total_len_copy ); if (total_len_copy NEQ malloc_len) { /* Corrupted packet -> drop it */ p_ul->drop_packet = TRUE; /* Clean up and free the descs */ del_descs (p_ul->first_desc_segment); p_ul->segment_offset = 0; p_ul->next_segment_desc = 0; p_ul->last_segment_pos = 0; p_ul->sended_segment_len = 0; p_ul->state_segment = NO_SEGMENTS; } else { p_ul->segment_id = p_ul->identity; p_ul->segment_offset = 0; build_ip_header ( desc_new->buffer, p_ul->segment_id, (UBYTE) p_ul->header_len, NORMAL_SERVICE, p_ul->ttl, src_addr, dest_addr, malloc_len, (USHORT) (p_ul->segment_offset >> 3), FLAG_NOT_SET, FLAG_SET, p_ul->segment_prot ); #ifndef _SIMULATION_ p_ul->identity++; #endif /* For the next fragment */ p_ul->segment_offset = (USHORT) (malloc_len - header_len_b); p_ul->next_segment_desc = (ULONG) desc; p_ul->last_segment_pos = pos_copy; } } /* Middle fragment */ else if (p_ul->sended_segment_len + p_ker->mtu < p_ul->list_len_segment + LEN_IP_HEADER_B) { T_desc2 * desc_new; USHORT pos_copy, total_len_copy, malloc_len; /* Make a new primitive for the fragment */ PALLOC (dti_data_req, DTI2_DATA_REQ); p_ul->dti_data_req = dti_data_req; /* Malloc the fragment desc */ malloc_len = p_ker->mtu; make_new_desc (& desc_new, malloc_len, FALSE); dti_data_req->desc_list2.first = (ULONG) desc_new; dti_data_req->desc_list2.list_len = malloc_len; desc_new->next = 0; /* Copy the data into the fragment desc */ desc = (T_desc2 *) p_ul->next_segment_desc; copy_from_descs_to_desc ( & desc, desc_new, (USHORT) (malloc_len - LEN_IP_HEADER_B), p_ul->last_segment_pos, LEN_IP_HEADER_B, & pos_copy, & total_len_copy ); if (total_len_copy NEQ malloc_len - LEN_IP_HEADER_B) { /* Corrupted packet -> drop it */ p_ul->drop_packet = TRUE; /* Clean up and free the descs */ del_descs (p_ul->first_desc_segment); p_ul->segment_offset = 0; p_ul->next_segment_desc = 0; p_ul->last_segment_pos = 0; p_ul->sended_segment_len = 0; p_ul->state_segment = NO_SEGMENTS; } else { /* Build the IP fragment */ UBYTE * ip_header_first = p_ul->first_desc_segment->buffer; dest_addr = GET_IP_DEST_ADDR (ip_header_first);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */ build_ip_header ( desc_new->buffer, p_ul->segment_id, MIN_HEADER_LEN, NORMAL_SERVICE, p_ul->ttl, src_addr, dest_addr, malloc_len, (USHORT) (p_ul->segment_offset >> 3), FLAG_NOT_SET, FLAG_SET, p_ul->segment_prot ); /* For the next fragment */ p_ul->segment_offset = (USHORT) (p_ul->segment_offset + malloc_len - LEN_IP_HEADER_B); p_ul->next_segment_desc = (ULONG) desc; p_ul->last_segment_pos = pos_copy; p_ul->sended_segment_len = (USHORT) (p_ul->sended_segment_len + malloc_len - LEN_IP_HEADER_B); } } else /* Last fragment */ { T_desc2 * desc_new; USHORT pos_copy, total_len_copy, malloc_len; /* Make a new primitive for the fragment */ PALLOC (dti_data_req, DTI2_DATA_REQ); p_ul->dti_data_req = dti_data_req; /* Calculate the correct len for fragment desc and malloc */ malloc_len = (USHORT) (LEN_IP_HEADER_B + p_ul->list_len_segment - p_ul->sended_segment_len); make_new_desc (& desc_new, malloc_len, FALSE); dti_data_req->desc_list2.first = (ULONG) desc_new; dti_data_req->desc_list2.list_len = malloc_len; desc_new->next = 0; /* Copy the data into the fragment desc */ desc = (T_desc2 *) p_ul->next_segment_desc; copy_from_descs_to_desc ( & desc, desc_new, (USHORT) (malloc_len - LEN_IP_HEADER_B), p_ul->last_segment_pos, LEN_IP_HEADER_B, & pos_copy, & total_len_copy ); if (total_len_copy NEQ malloc_len - LEN_IP_HEADER_B) { /* Corrupted packet -> drop it */ p_ul->drop_packet = TRUE; /* Clean up and free the descs */ del_descs (p_ul->first_desc_segment); p_ul->segment_offset = 0; p_ul->next_segment_desc = 0; p_ul->last_segment_pos = 0; p_ul->sended_segment_len = 0; p_ul->state_segment = NO_SEGMENTS; } else { /* Build the fragment header */ UBYTE * ip_header_first = p_ul->first_desc_segment->buffer; dest_addr = GET_IP_DEST_ADDR (ip_header_first);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */ build_ip_header ( desc_new->buffer, p_ul->segment_id, MIN_HEADER_LEN, NORMAL_SERVICE, p_ul->ttl, src_addr, dest_addr, malloc_len, (USHORT) (p_ul->segment_offset >> 3), FLAG_NOT_SET, FLAG_NOT_SET, p_ul->segment_prot ); /* Clean up and free the descs */ del_descs (p_ul->first_desc_segment); p_ul->segment_offset = 0; p_ul->next_segment_desc = 0; p_ul->last_segment_pos = 0; p_ul->sended_segment_len = 0; p_ul->state_segment = NO_SEGMENTS; } } } break; default: break; } } else { data_ind = p_dl->dti_data_ind; /* Compute DL packets */ switch (select) { /* Ping request */ case B_ICMP_ECHO_REPLY: { USHORT header_len_b; PPASS (data_ind, data_request, DTI2_DATA_REQ); desc_list = & data_request->desc_list2; desc = (T_desc2 *) desc_list->first; ip_header = desc->buffer; header_len_b = (USHORT) GET_IP_HEADER_LEN_B (ip_header); dest_addr = GET_IP_SOURCE_ADDR (ip_header);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */ build_icmp_packet ( (UBYTE) header_len_b, ICMP_TYP_ECHO_REPLY, ICMP_CODE_ECHO_REPLY, p_ul->ttl, ip_header, p_ul->identity, dest_addr, src_addr, desc_list ); #ifndef _SIMULATION_ p_ul->identity++; #endif p_ker->icmp_dti_data_req = data_request; } break; case B_ICMP_REASSEMBLE_TIMEOUT: { /* Datagram for ICMP - reassembly - message */ data_ind = p_dl->data_ind_reassembly[p_dl->pos_server]; { PPASS (data_ind, data_request, DTI2_DATA_REQ); build_icmp_with_payload ( data_request, p_ul->identity, p_ul->ttl, p_ker->source_addr, ICMP_TYP_TIME_EXCEDED, ICMP_CODE_FRAGM_TIME_EXC ); #ifndef _SIMULATION_ p_ul->identity++; #endif p_ker->icmp_dti_data_req = data_request; } } break; case B_ICMP_NO_FORWARD: { /* No destination address - build ICMP frame */ PPASS (data_ind, data_request, DTI2_DATA_REQ); build_icmp_with_payload ( data_request, p_ul->identity, p_ul->ttl, p_ker->source_addr, ICMP_TYP_DEST_URECHBL, ICMP_CODE_NO_HOST ); #ifndef _SIMULATION_ p_ul->identity++; #endif p_ker->icmp_dti_data_req = data_request; } break; default: break; } } } /* +--------------------------------------------------------------------+ | PROJECT : GSM-FaD (8444) MODULE : IP_KERF | | STATE : code ROUTINE : check_ip_address | +--------------------------------------------------------------------+ * * Check the IP address */ void check_ip_address ( BOOL * addr_type_dest, BOOL * addr_type_src, ULONG dest_addr, ULONG src_addr ) { UBYTE i; UBYTE b_dest_addr[4], b_src_addr[4], first_nibbl_dest, first_nibbl_src; #define BCAST 0xFF #define LOOP_BACK 0x7F #define DEFAULT_ROUTE 0 #define CLASS_A 0x0 #define CLASS_B 0x2 #define CLASS_C 0x6 #define MULTICAST 0xE #define CLASS_E 0xF #define M_CAST_FF 0xFFFFFFFF TRACE_FUNCTION ("check_ip_address()"); ip_addr_int_to_byte (b_dest_addr, dest_addr); ip_addr_int_to_byte (b_src_addr, src_addr); first_nibbl_dest = (UBYTE) (b_dest_addr[0] >> 4); first_nibbl_src = (UBYTE) (b_src_addr[0] >> 4); for (i=0; i < MAX_ADDR_TYPES; i++) { addr_type_dest[i] = FALSE; addr_type_src[i] = FALSE; } /* Check if broadcast address */ if (dest_addr EQ M_CAST_FF) addr_type_dest[BCAST_ADDR_255] = TRUE; if (src_addr EQ M_CAST_FF) addr_type_src[BCAST_ADDR_255] = TRUE; /* Correct destination address? */ if (dest_addr NEQ src_addr) { addr_type_dest[NO_DEST_ADDR] = TRUE; addr_type_src[NO_DEST_ADDR] = TRUE; } /* Loop-back address? */ if (b_dest_addr[0] EQ LOOP_BACK) addr_type_dest[LOOP_BACK_ADDR] = TRUE; if (b_src_addr[0] EQ LOOP_BACK) addr_type_src[LOOP_BACK_ADDR] = TRUE; /* Check kind of class */ if ((first_nibbl_src >> 3) EQ CLASS_A) addr_type_src[CLASS_A_ADDR] = TRUE; if ((first_nibbl_dest >> 3) EQ CLASS_A) addr_type_dest[CLASS_A_ADDR] = TRUE; if ((first_nibbl_src >> 2) EQ CLASS_B) addr_type_src[CLASS_B_ADDR] = TRUE; if ((first_nibbl_dest >> 2) EQ CLASS_B) addr_type_dest[CLASS_B_ADDR] = TRUE; if ((first_nibbl_src >> 1) EQ CLASS_C) addr_type_src[CLASS_C_ADDR] = TRUE; if ((first_nibbl_dest >> 1) EQ CLASS_C) addr_type_dest[CLASS_C_ADDR] = TRUE; if (first_nibbl_src EQ CLASS_E AND dest_addr NEQ M_CAST_FF) addr_type_src[CLASS_E_ADDR] = TRUE; if (first_nibbl_dest EQ CLASS_E AND src_addr NEQ M_CAST_FF) addr_type_dest[CLASS_E_ADDR] = TRUE; /* Multicast or class D */ if (first_nibbl_dest EQ MULTICAST) addr_type_dest[MCAST_ADDR] = TRUE; if (first_nibbl_src EQ MULTICAST) addr_type_src[MCAST_ADDR] = TRUE; /* Default route */ if (dest_addr EQ DEFAULT_ROUTE) addr_type_dest[DEFAULT_R_ADDR] = TRUE; if (src_addr EQ DEFAULT_ROUTE) addr_type_src[DEFAULT_R_ADDR] = TRUE; /* Bad address? */ if ( addr_type_src[BCAST_ADDR_255] OR addr_type_src[LOOP_BACK_ADDR] OR addr_type_src[DEFAULT_R_ADDR] ) { addr_type_src[BAD_UL_SRC_ADDR] = TRUE; addr_type_src[BAD_DL_SRC_ADDR] = TRUE; } if ( addr_type_dest[BCAST_ADDR_255] OR addr_type_dest[LOOP_BACK_ADDR] OR addr_type_dest[DEFAULT_R_ADDR] ) { addr_type_dest[BAD_UL_DEST_ADDR] = TRUE; addr_type_dest[BAD_DL_DEST_ADDR] = TRUE; } } /* Internet checksum calculations as needed in IP and UDP. * See RFC 1071 for details. * * USHORT inet_checksum (UBYTE * block, USHORT len) * Computes the Internet checksum over a simple data block. * * USHORT desc_checksum ( * T_desc_list2 * dlist, * USHORT start_offset, * ULONG start_value * ) * Computes the Internet checksum over a DTI descriptor list, * beginning at start_offset and with start_value. */ #define LITTLE_ENDIAN /* Change this for big-endian mode. */ /** Computes the Internet checksum [RFC 1071] over a simple data block. * * @param block pointer to data block * @param len length of the block in octets * @return the checksum */ USHORT inet_checksum (UBYTE * block, USHORT len) { BOOL have_leftover = len % 2; /* If non-zero, there is a leftover * octet at the end of the (odd-sized) * data block. */ ULONG value; /* Value to add. (Since we know * nothing about the alignment of the * block, we can't read the USHORTs * directly from the block.) */ ULONG checksum = 0; /* Checksum accumulator. */ len >>= 1; /* Count words now, not octets. */ while (len--) { /* Because we must read the data bytewise, we cannot profit from * the independency of endianness of the original algorithm. * That means that we have to make two different cases for big * endian and little endian. */ #if defined LITTLE_ENDIAN /*lint -e{661} (Warning -- access of out-of-bounds pointer) */ value = block[1]<<8 | block[0]; #elif defined BIG_ENDIAN /*lint -e{662} (Warning -- creation of out-of-bounds pointer) */ value = block[0]<<8 | block[1]; #else #error "LITTLE_ENDIAN or BIG_ENDIAN must be defined." #endif checksum += value; /*lint -e{662} (Warning -- creation of out-of-bounds pointer) */ block +=2; } if (have_leftover) /*lint -e{661} (Warning -- access of out-of-bounds pointer) */ checksum += *block; /* Fold into 16 bits. */ while (checksum >> 16) checksum = (checksum & 0xffff) + (checksum >> 16); return (USHORT) ~checksum; } /** Computes a part of an Internet checksum over a data block. A * leftover octet from a previous partial calculation is taken into * account. If an octet is left over, it is returned as well as the * fact that there is a leftover octet. This function is intended to * be called only by desc_checksum() and partial_checksum(). * * @param block pointer to data block * @param len length of the block in octets * @param sum checksum value to begin with * @param have_leftover_ptr if non-zero, a leftover octet is in *leftover_ptr * @param leftover_ptr pointer to leftover octet; valid on input and * output iff *have_leftover_ptr * @return the part of the sum calculated */ static ULONG checksum_block_part ( UBYTE * block, USHORT len, ULONG sum, BOOL * have_leftover_ptr, UBYTE * leftover_ptr ) { /* This function is as complicated as it is for two reasons: * * (a) Each block may have an even or odd number of octets. Because * this checksum is 16-bit based, an octet may be left over from the * previous calculation and must be taken into account. Also in this * calculation an octet may be left over. This fact and the value of * the octet must be made known to the caller. * * (b) We must not make any assumptions about the alignment of the * block. Therefore, in order not to cause alignment problems, all * 16-bit values must be read bytewise. */ ULONG value; /* 16-bit value to be summed up */ TRACE_FUNCTION ("checksum_block_part()"); /* Previous calculation may have left over an octet. */ if (*have_leftover_ptr) { if (len == 0) return sum; /* See comment in inet_checksum() above for an explanation. */ #if defined LITTLE_ENDIAN value = (*block++ << 8) | *leftover_ptr; #elif defined BIG_ENDIAN value = (*leftover_ptr << 8) | *block++; #else #error "LITTLE_ENDIAN or BIG_ENDIAN must be defined." #endif len--; sum += value; } /* Main loop over word values. */ *have_leftover_ptr = len % 2; len >>= 1; while (len--) { /* See comment in inet_checksum() above for an explanation. */ #if defined LITTLE_ENDIAN value = block[1]<<8 | block[0]; #elif defined BIG_ENDIAN value = block[0]<<8 | block[1]; #else #error "LITTLE_ENDIAN or BIG_ENDIAN must be defined." #endif sum += value; block +=2; } /* Check for leftover octet. */ if (*have_leftover_ptr) *leftover_ptr = *block; return sum; } /** Compute a partial Internet checksum to be used as a astart_value * for desc_checksum. The block must have even length. * * @param block data block to compute the checksum over * @param len length of the block * @return the partial sum calculated */ ULONG partial_checksum (UBYTE * block, USHORT len) { BOOL dummy1 = 0; /* Needed to call checksum_block_part(). */ UBYTE dummy2 = 0; return checksum_block_part (block, len, 0, & dummy1, & dummy2); } /** Computes the Internet checksum over a DTI descriptor list. There * may be a value from a previous partial calculation that is added to * the sum as a start value. The function relies on the data length * being at least start_offset. * * @param dlist descriptor list containing the data * @param start_offset beginning position of interesting data * @param start_value value from previous partial checksum calculation * @return the checksum value */ USHORT desc_checksum ( T_desc_list2 * dlist, USHORT start_offset, ULONG start_value ) { ULONG checksum = start_value; /* The checksum to be calculated. */ T_desc2 * desc_p; /* Pointer to current descriptor. */ BOOL have_leftover = 0; /* True iff we have a leftover octet * from the previous partial sum. */ UBYTE leftover_octet = 0; /* An octet left over from the * previous partial sum. */ TRACE_FUNCTION ("desc_checksum()"); /* Calculating the sum of the first buffer, we have to take the * start offset into account. This includes finding the descriptor * the offset lies in. */ desc_p = (T_desc2 *) dlist->first; while (start_offset > desc_p->len) { start_offset = (USHORT) (start_offset - desc_p->len); desc_p = (T_desc2 *) desc_p->next; } checksum = checksum_block_part ( desc_p->buffer + start_offset, (USHORT) (desc_p->len - start_offset), checksum, & have_leftover, & leftover_octet ); /* Now loop over the other descriptors. */ for ( desc_p = (T_desc2 *) desc_p->next; desc_p != 0; desc_p = (T_desc2 *) desc_p->next ) { checksum = checksum_block_part ( desc_p->buffer, desc_p->len, checksum, & have_leftover, & leftover_octet ); } if (have_leftover) checksum += leftover_octet; /* Fold into 16 bits. */ while (checksum >> 16) checksum = (checksum & 0xffff) + (checksum >> 16); return (USHORT) ~checksum; } /*-------------------------------------------------------------------------*/