Files
openairinterface5g/openair2/NAS/DRIVER/CELLULAR/NASRG/nasrg_classifier.c
T
Lionel Gauthier c60dc45b2b Changed uX, uX_t sX, sX_t to uinX_t
Cleaned some PDCP/driver code

types parameters and vars

Please see openair2/COMMON/platform_types.h for simple coding rules.

please declare prototypes of functions in .h and include .h files in where the function is used and where it is implemented.



git-svn-id: http://svn.eurecom.fr/openair4G/trunk@5096 818b1a75-f10b-46b9-bf7c-635c3b92a50f
2014-02-28 13:03:10 +00:00

1017 lines
38 KiB
C
Executable File

/***************************************************************************
nasrg_classifier.c - description
***************************************************************************
Eurecom OpenAirInterface 2
Copyright(c) 1999 - 2013 Eurecom
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information
Openair Admin: openair_admin@eurecom.fr
Openair Tech : openair_tech@eurecom.fr
Forums : http://forums.eurecom.fsr/openairinterface
Address : Eurecom, 450 route des Chappes, 06410 Biot Sophia Antipolis, France
*******************************************************************************/
/*! \file nasrg_classifier.c
* \brief Flow classification functions for OpenAirInterface CELLULAR version - RG
* \author michelle.wetterwald, navid.nikaein, raymond.knopp, Lionel Gauthier
* \company Eurecom
* \email: michelle.wetterwald@eurecom.fr, raymond.knopp@eurecom.fr, navid.nikaein@eurecom.fr, lionel.gauthier@eurecom.fr
*/
/*******************************************************************************/
#include "nasrg_variables.h"
#include "nasrg_proto.h"
#include <net/ip6_fib.h>
#include <net/route.h>
#define IN_CLASSA(a) ((((long int) (a)) & 0x80000000) == 0)
#define IN_CLASSB(a) ((((long int) (a)) & 0xc0000000) == 0x80000000)
#define IN_CLASSC(a) ((((long int) (a)) & 0xe0000000) == 0xc0000000)
#define IN_CLASSD(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000)
/* Address to accept any incoming messages. */
#define INADDR_ANY ((unsigned long int) 0x00000000)
#define NIPADDR(addr) \
(uint8_t)(addr & 0x000000FF), \
(uint8_t)((addr & 0x0000FF00) >> 8), \
(uint8_t)((addr & 0x00FF0000) >> 16), \
(uint8_t)((addr & 0xFF000000) >> 24)
#define NIP6ADDR(addr) \
ntohs((addr)->s6_addr16[0]), \
ntohs((addr)->s6_addr16[1]), \
ntohs((addr)->s6_addr16[2]), \
ntohs((addr)->s6_addr16[3]), \
ntohs((addr)->s6_addr16[4]), \
ntohs((addr)->s6_addr16[5]), \
ntohs((addr)->s6_addr16[6]), \
ntohs((addr)->s6_addr16[7])
#define IN6_IS_ADDR_UNSPECIFIED(a) \
(((__const uint32_t *) (a))[0] == 0 \
&& ((__const uint32_t *) (a))[1] == 0 \
&& ((__const uint32_t *) (a))[2] == 0 \
&& ((__const uint32_t *) (a))[3] == 0)
#define IN6_ARE_ADDR_MASKED_EQUAL(a,b,m) \
(((((__const uint32_t *) (a))[0] & (((__const uint32_t *) (m))[0])) == (((__const uint32_t *) (b))[0] & (((__const uint32_t *) (m))[0]))) \
&& ((((__const uint32_t *) (a))[1] & (((__const uint32_t *) (m))[1])) == (((__const uint32_t *) (b))[1] & (((__const uint32_t *) (m))[1]))) \
&& ((((__const uint32_t *) (a))[2] & (((__const uint32_t *) (m))[2])) == (((__const uint32_t *) (b))[2] & (((__const uint32_t *) (m))[2]))) \
&& ((((__const uint32_t *) (a))[3] & (((__const uint32_t *) (m))[3])) == (((__const uint32_t *) (b))[3] & (((__const uint32_t *) (m))[3]))))
#define IN_ARE_ADDR_MASKED_EQUAL(a,b,m) \
(((((__const uint8_t *) (a))[0] & (((__const uint8_t *) (m))[0])) == (((__const uint8_t *) (b))[0] & (((__const uint8_t *) (m))[0]))) \
&& ((((__const uint8_t *) (a))[1] & (((__const uint8_t *) (m))[1])) == (((__const uint8_t *) (b))[1] & (((__const uint8_t *) (m))[1]))) \
&& ((((__const uint8_t *) (a))[2] & (((__const uint8_t *) (m))[2])) == (((__const uint8_t *) (b))[2] & (((__const uint8_t *) (m))[2]))) \
&& ((((__const uint8_t *) (a))[3] & (((__const uint8_t *) (m))[3])) == (((__const uint8_t *) (b))[3] & (((__const uint8_t *) (m))[3]))))
//---------------------------------------------------------------------------
void nasrg_create_mask_ipv6_addr(struct in6_addr *masked_addrP, int prefix_len){
//---------------------------------------------------------------------------
int u6_addr8_index;
int u6_addr1_index;
int index;
masked_addrP->s6_addr32[0] = 0xFFFFFFFF;
masked_addrP->s6_addr32[1] = 0xFFFFFFFF;
masked_addrP->s6_addr32[2] = 0xFFFFFFFF;
masked_addrP->s6_addr32[3] = 0xFFFFFFFF;
u6_addr8_index = prefix_len >> 3;
u6_addr1_index = prefix_len & 0x07;
for (index = u6_addr8_index + 1; index < 16; index++) {
masked_addrP->s6_addr[index] = 0;
}
if (u6_addr1_index > 0) {
masked_addrP->s6_addr[u6_addr8_index] = 0xFF << (8-u6_addr1_index);
}
#ifdef NAS_DEBUG_CLASS
//printk("nasrg_create_mask_ipv6_addr: MASK = %X:%X:%X:%X:%X:%X:%X:%X\n",NIP6ADDR(masked_addrP));
#endif
}
//---------------------------------------------------------------------------
void nasrg_create_mask_ipv4_addr(struct in_addr *masked_addrP, int prefix_len){
//---------------------------------------------------------------------------
if (prefix_len > 32) {
prefix_len = 32;
}
masked_addrP->s_addr = 0xFFFFFFFF << (32 - prefix_len);
#ifdef NAS_DEBUG_CLASS
//printk("nasrg_create_mask_ipv4_addr: MASK = %d.%d.%d.%d\n",NIPADDR(masked_addrP));
#endif
return;
}
//---------------------------------------------------------------------------
// Add a new classifier rule (send direction)
struct classifier_entity *nasrg_CLASS_add_sclassifier(struct cx_entity *cx, uint8_t dscp, uint16_t classref){
//---------------------------------------------------------------------------
struct classifier_entity *gc;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_add_sclassifier: begin for dscp %d, classref %d\n", dscp,classref);
#endif
if (cx==NULL){
printk("nasrg_CLASS_add_sclassifier - input parameter cx is NULL \n");
return NULL;
}
//***
for (gc=cx->sclassifier[dscp]; gc!=NULL; gc=gc->next){
if (gc->classref==classref){
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_add_sclassifier: classifier already exist for dscp %d, classref %d\n",dscp,classref);
#endif
return gc;
}
}
gc=(struct classifier_entity *)kmalloc(sizeof(struct classifier_entity), GFP_ATOMIC);
if (gc==NULL)
return NULL;
memset(gc, 0, sizeof(struct classifier_entity));
gc->next=cx->sclassifier[dscp];
gc->classref=classref;
cx->sclassifier[dscp]=gc;
++cx->nsclassifier;
++gpriv->next_sclassref; //increment send classref index - MW 15/01/07
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_add_sclassifier: classifier created for dscp %d, classref %d\n",dscp,classref);
#endif
return gc;
}
//---------------------------------------------------------------------------
// Add a new classifier rule (receive direction)
struct classifier_entity *nasrg_CLASS_add_rclassifier(uint8_t dscp, uint16_t classref){
//---------------------------------------------------------------------------
struct classifier_entity *gc;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_add_rclassifier: begin\n");
#endif
//***
for (gc=gpriv->rclassifier[dscp]; gc!=NULL; gc=gc->next)
{
if (gc->classref==classref){
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_add_rclassifier: classifier already exist for dscp %d, classref %d\n",dscp,classref);
#endif
return gc;
}
}
gc=(struct classifier_entity *)kmalloc(sizeof(struct classifier_entity), GFP_KERNEL);
if (gc==NULL)
return NULL;
gc->next=gpriv->rclassifier[dscp];
gc->classref=classref;
gpriv->rclassifier[dscp]=gc;
++gpriv->nrclassifier;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_add_rclassifier: classifier created for dscp %d, classref %d\n",dscp,classref);
#endif
return gc;
}
//---------------------------------------------------------------------------
// Add a new classifier rule (mbms direction)
struct classifier_entity *nasrg_CLASS_add_mbmsclassifier(int mbms_ix, uint16_t classref){
//---------------------------------------------------------------------------
struct classifier_entity *gc;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_add_mbmsclassifier: begin\n");
#endif
//***
for (gc=gpriv->mbmsclassifier[mbms_ix]; gc!=NULL; gc=gc->next)
{
if (gc->classref==classref){
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_add_mbmsclassifier: classifier already exist for service %d, classref %d\n",mbms_ix,classref);
#endif
return gc;
}
}
gc=(struct classifier_entity *)kmalloc(sizeof(struct classifier_entity), GFP_ATOMIC);
if (gc==NULL)
return NULL;
gc->next=gpriv->mbmsclassifier[mbms_ix];
gc->classref=classref;
gpriv->mbmsclassifier[mbms_ix]=gc;
++gpriv->nmbmsclassifier;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_add_mbmsclassifier: classifier created for service index %d, classref %d\n",mbms_ix,classref);
#endif
return gc;
}
//---------------------------------------------------------------------------
void nasrg_CLASS_flush_sclassifier(struct cx_entity *cx){
//---------------------------------------------------------------------------
uint8_t dscpi;
struct classifier_entity *gc;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_flush_sclassifier: begin\n");
#endif
if (cx==NULL){
printk("nasrg_CLASS_flush_sclassifier - input parameter cx is NULL \n");
return;
}
//***
for (dscpi=0; dscpi<NAS_DSCP_MAX; ++dscpi){
for (gc=cx->sclassifier[dscpi]; gc!=NULL; gc=cx->sclassifier[dscpi]){
cx->sclassifier[dscpi]=gc->next;
kfree(gc);
}
}
cx->nsclassifier=0;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_flush_sclassifier: end\n");
#endif
}
//---------------------------------------------------------------------------
void nasrg_CLASS_flush_rclassifier(){
//---------------------------------------------------------------------------
uint8_t dscpi;
struct classifier_entity *gc;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_flush_rclassifier: begin\n");
#endif
//***
for (dscpi=0; dscpi<NAS_DSCP_MAX; ++dscpi){
for (gc=gpriv->rclassifier[dscpi]; gc!=NULL; gc=gpriv->rclassifier[dscpi]){
gpriv->rclassifier[dscpi]=gc->next;
kfree(gc);
}
}
gpriv->nrclassifier=0;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_flush_rclassifier: end\n");
#endif
}
//---------------------------------------------------------------------------
void nasrg_CLASS_flush_mbmsclassifier(){
//---------------------------------------------------------------------------
int mbmsi;
struct classifier_entity *gc;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_flush_mbmsclassifier: begin\n");
#endif
//***
for (mbmsi=0; mbmsi<NASRG_MBMS_SVCES_MAX; ++mbmsi){
for (gc=gpriv->mbmsclassifier[mbmsi]; gc!=NULL; gc=gpriv->mbmsclassifier[mbmsi]){
gpriv->mbmsclassifier[mbmsi]=gc->next;
kfree(gc);
}
}
gpriv->nmbmsclassifier=0;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_flush_mbmsclassifier: end\n");
#endif
}
//---------------------------------------------------------------------------
// Delete a classifier rule (send direction)
void nasrg_CLASS_del_sclassifier(struct cx_entity *cx, uint8_t dscp, uint16_t classref){
//---------------------------------------------------------------------------
struct classifier_entity *p,*np;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_del_sclassifier: begin\n");
#endif
if (cx==NULL){
printk("nasrg_CLASS_del_sclassifier - input parameter cx is NULL \n");
return;
}
//***
p=cx->sclassifier[dscp];
if (p==NULL)
return;
if (p->classref==classref){
cx->sclassifier[dscp]=p->next;
kfree(p);
--cx->nsclassifier;
return;
}
for (np=p->next; np!=NULL; p=np){
if (np->classref==classref){
p->next=np->next;
kfree(np);
--cx->nsclassifier;
return;
}
}
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_del_sclassifier: end\n");
#endif
}
//---------------------------------------------------------------------------
// Delete a classifier rule (receive direction)
void nasrg_CLASS_del_rclassifier(uint8_t dscp, uint16_t classref){
//---------------------------------------------------------------------------
struct classifier_entity *p,*np;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_del_rclassifier: begin\n");
#endif
//***
p=gpriv->rclassifier[dscp];
if (p==NULL)
return;
if (p->classref==classref){
gpriv->rclassifier[dscp]=p->next;
kfree(p);
--gpriv->nrclassifier;
return;
}
for (np=p->next; np!=NULL; p=np){
if (np->classref==classref){
p->next=np->next;
kfree(np);
--gpriv->nrclassifier;
return;
}
}
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_del_rclassifier: end\n");
#endif
}
//---------------------------------------------------------------------------
// Delete a classifier rule (mbms direction)
void nasrg_CLASS_del_mbmsclassifier(int mbms_ix, uint16_t classref){
//---------------------------------------------------------------------------
struct classifier_entity *p,*np;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_del_mbmsclassifier: begin\n");
#endif
//***
p=gpriv->mbmsclassifier[mbms_ix];
if (p==NULL)
return;
if (p->classref==classref){
gpriv->mbmsclassifier[mbms_ix]=p->next;
kfree(p);
--gpriv->nmbmsclassifier;
return;
}
for (np=p->next; np!=NULL; p=np){
if (np->classref==classref){
p->next=np->next;
kfree(np);
--gpriv->nmbmsclassifier;
return;
}
}
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_del_mbmsclassifier: end\n");
#endif
}
/* ORIGINAL VERSION
//---------------------------------------------------------------------------
// Search the entity with the IPv4 address 'addr'
struct cx_entity *nasrg_CLASS_cx4(struct sk_buff *skb){
//---------------------------------------------------------------------------
uint8_t cxi;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_cx4: begin\n");
#endif
cxi=0;
return gpriv->cx+cxi;
//#endif
}*/
//---------------------------------------------------------------------------
// Search the entity with the IPv4 address 'addr'
struct cx_entity *nasrg_CLASS_cx4(struct sk_buff *skb, unsigned char dscp, int *paddr_type, unsigned char *cx_index) {
//---------------------------------------------------------------------------
unsigned char cxi;
uint32_t daddr;
struct cx_entity *cx=NULL;
struct classifier_entity *pclassifier=NULL;
struct in_addr masked_addr;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_cx4: begin\n");
#endif
if (skb!=NULL) {
daddr = ((struct iphdr*)(skb_network_header(skb)))->daddr;
if (daddr != INADDR_ANY) {
#ifdef NAS_DEBUG_CLASS
printk("SOURCE ADDR %d.%d.%d.%d",NIPADDR(ip_hdr(skb)->saddr));
printk(" DEST ADDR %d.%d.%d.%d\n",NIPADDR(ip_hdr(skb)->daddr));
#endif
if (ipv4_is_multicast(ip_hdr(skb)->daddr)) {
// TO BE CHECKED
*paddr_type = NAS_IPV4_ADDR_MC_SIGNALLING;
} else {
if (ipv4_is_lbcast(ip_hdr(skb)->daddr)) {
// TO BE CHECKED
*paddr_type = NAS_IPV4_ADDR_BROADCAST;
} else {
if (IN_CLASSA(ip_hdr(skb)->daddr) || IN_CLASSB(ip_hdr(skb)->daddr) || IN_CLASSC(ip_hdr(skb)->daddr)) {
*paddr_type = NAS_IPV4_ADDR_UNICAST;
for (cxi=*cx_index; cxi<NAS_CX_MAX; ++cxi) {
(*cx_index)++;
pclassifier = gpriv->cx[cxi].sclassifier[dscp];
while (pclassifier!=NULL) {
// verify that this is an IPv4 classifier
if ((pclassifier->version == NAS_VERSION_4) || (pclassifier->version == NAS_VERSION_DEFAULT)) {
nasrg_create_mask_ipv4_addr(&masked_addr, pclassifier->dplen);
if (IN_ARE_ADDR_MASKED_EQUAL(&ip_hdr(skb)->daddr, &(pclassifier->daddr.ipv4), &masked_addr)) {
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_cx4: IP MASK MATCHED: found cx %d: %d.%d.%d.%d/%d\n",cxi, NIPADDR(pclassifier->daddr.ipv4), pclassifier->dplen);
#endif
return &gpriv->cx[cxi];
}
}
// goto to next classification rule for the connection
pclassifier = pclassifier->next;
}
}
} else {
*paddr_type = NAS_IPV4_ADDR_UNKNOWN;
}
}
}
}
}
return cx;
}
/* ORIGINAL VERSION
//---------------------------------------------------------------------------
// Search the entity corresponding to destination address in IPv6 header
struct cx_entity *nasrg_CLASS_cx6(struct sk_buff *skb, int* paddr_type, int* pmbms_ix){
//---------------------------------------------------------------------------
struct cx_entity * cx=NULL;
uint8_t cxi;
uint32_t mc_addr_hdr, uni_ifid1, uni_ifid2;
//int addr_type = NASRG_ADDR_UNKNOWN;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_cx6: begin\n");
#endif
if (!skb){
printk("nasrg_CLASS_cx6 - input parameter skb is NULL \n");
return cx;
}
*paddr_type = NASRG_ADDR_UNKNOWN;
//mc_addr_hdr = ntohl(skb->nh.ipv6h->daddr.in6_u.u6_addr32[0]);
mc_addr_hdr = ntohl(ipv6_hdr(skb)->daddr.in6_u.u6_addr32[0]);
// First check if multicast [1st octet is FF]
if ((mc_addr_hdr & 0xFF000000) == 0xFF000000) {
// packet type according to the scope of the multicast packet
// we don't consider RPT bits in second octet [maybe done later if needed]
switch(mc_addr_hdr & 0x000F0000) {
case (0x00020000):
*paddr_type = NASRG_ADDR_MC_SIGNALLING;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_cx6: multicast packet - signalling \n");
#endif
break;
case (0x000E0000):
*paddr_type = NASRG_ADDR_MC_MBMS;
*pmbms_ix = 0;
cx=gpriv->cx; // MBMS associate to Mobile 0
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_cx6: multicast packet - MBMS data \n");
#endif
break;
default:
*paddr_type = NASRG_ADDR_UNKNOWN;
*pmbms_ix = NASRG_MBMS_SVCES_MAX;
}
// This is not multicast, so we should be able to identify the MT
}else{
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_cx6: unicast packet\n");
#endif
*paddr_type = NASRG_ADDR_UNICAST;
uni_ifid1 = ntohl(ipv6_hdr(skb)->daddr.in6_u.u6_addr32[2]);
uni_ifid2 = ntohl(ipv6_hdr(skb)->daddr.in6_u.u6_addr32[3]);
for (cxi=0; cxi<NAS_CX_MAX; cxi++){
cx=gpriv->cx+cxi;
#ifdef NAS_DEBUG_SEND_DETAIL
printk("nasrg_CLASS_cx6: Compared addresses \n");
printk(" Daddr[2] %ul, Daddr[3] %ul\n",
ipv6_hdr(skb)->daddr.in6_u.u6_addr32[2],ipv6_hdr(skb)->daddr.in6_u.u6_addr32[3]);
printk(" ntohl Daddr[2] %ul, Daddr[3] %ul\n",uni_ifid1,uni_ifid2);
printk(" IIF[0] %ul, IIF[1] %ul\n",cx->iid6[0],cx->iid6[1]);
printk(" htonl IIF[0] %ul, IIF[1] %ul\n",htonl(cx->iid6[0]),htonl(cx->iid6[1]));
#endif
if (((cx->iid6[0] == uni_ifid1)&&(cx->iid6[1] == uni_ifid2))
|| ((htonl(cx->iid6[0]) == uni_ifid1)&&(htonl(cx->iid6[1]) == uni_ifid2))){
return cx;
}
}
}
return cx;
}*/
//---------------------------------------------------------------------------
// Search the entity with the IPv6 address 'addr'
// Navid: the ipv6 classifier is not fully tested
struct cx_entity *nasrg_CLASS_cx6(struct sk_buff *skb, unsigned char dscp, int *paddr_type, unsigned char *cx_index, int* pmbms_ix) {
//---------------------------------------------------------------------------
uint8_t cxi;
struct cx_entity *cx = NULL;
struct classifier_entity *sclassifier= NULL;
uint32_t mc_addr_hdr;
struct in6_addr masked_addr;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_cx6: begin\n");
#endif
if (skb) {
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_cx6: SOURCE ADDR %X:%X:%X:%X:%X:%X:%X:%X",NIP6ADDR(&(ipv6_hdr(skb)->saddr)));
printk(" DEST ADDR %X:%X:%X:%X:%X:%X:%X:%X\n",NIP6ADDR(&(ipv6_hdr(skb)->daddr)));
#endif
mc_addr_hdr = ntohl(ipv6_hdr(skb)->daddr.in6_u.u6_addr32[0]);
// First check if multicast [1st octet is FF]
if ((mc_addr_hdr & 0xFF000000) == 0xFF000000) {
// packet type according to the scope of the multicast packet
// we don't consider RPT bits in second octet [maybe done later if needed]
switch(mc_addr_hdr & 0x000F0000) {
case (0x00020000):
*paddr_type = NAS_IPV6_ADDR_MC_SIGNALLING;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_cx6: multicast packet - signalling \n");
#endif
break;
case (0x000E0000):
*paddr_type = NAS_IPV6_ADDR_MC_MBMS;
*pmbms_ix = 0;
cx=gpriv->cx; // MBMS associate to Mobile 0
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_cx6: multicast packet - MBMS data \n");
#endif
break;
default:
printk("nasrg_CLASS_cx6: default multicast\n");
*paddr_type = NAS_IPV6_ADDR_UNKNOWN;
*pmbms_ix = NASRG_MBMS_SVCES_MAX;
}
} else {
// This is not multicast, so we should be able to identify the MT
*paddr_type = NAS_IPV6_ADDR_UNICAST;
for (cxi=*cx_index; cxi<NAS_CX_MAX; cxi++) {
//cxi = 0;
(*cx_index)++;
sclassifier = gpriv->cx[cxi].sclassifier[dscp];
while (sclassifier!=NULL) {
// verify that this is an IPv6 classifier
if ((sclassifier->version == NAS_VERSION_6) || (sclassifier->version == NAS_VERSION_DEFAULT)) {
/*LGif (IN6_IS_ADDR_UNSPECIFIED(&(sclassifier->daddr.ipv6))) {
printk("nas_CLASS_cx6: addr is null \n");
sclassifier = sclassifier->next;
continue;
}*/
#ifdef NAS_DEBUG_CLASS
printk("cx %d : DSCP %d %X:%X:%X:%X:%X:%X:%X:%X\n",cxi, dscp, NIP6ADDR(&(sclassifier->daddr.ipv6)));
#endif //NAS_DEBUG_CLASS
//if ((dst = (unsigned int*)&(((struct rt6_info *)skbdst)->rt6i_gateway)) == 0){
// LG: STRANGE
if (IN6_IS_ADDR_UNSPECIFIED(&ipv6_hdr(skb)->daddr)) {
printk("nasrg_CLASS_cx6: dst addr is null \n");
sclassifier = sclassifier->next;
continue;
}
nasrg_create_mask_ipv6_addr(&masked_addr, sclassifier->dplen);
// Modified MW to check only the iid6
masked_addr.s6_addr32[0] = 0x00000000;
masked_addr.s6_addr32[1] = 0x00000000;
if (IN6_ARE_ADDR_MASKED_EQUAL(&ipv6_hdr(skb)->daddr, &(sclassifier->daddr.ipv6), &masked_addr)) {
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_cx6: found cx %d: %X:%X:%X:%X:%X:%X:%X:%X\n",cxi, NIP6ADDR(&(sclassifier->daddr.ipv6)));
#endif //NAS_DEBUG_CLASS
return &gpriv->cx[cxi];
}
}
// Go to next classifier entry for connection
sclassifier = sclassifier->next;
}
}
}
}
//printk("nas_CLASS_cx6 NOT FOUND: %X:%X:%X:%X:%X:%X:%X:%X\n",NIP6ADDR(&ipv6_hdr(skb)->daddr));
return cx;
}
//---------------------------------------------------------------------------
// Search the sending function for IP Packet
void nasrg_CLASS_send(struct sk_buff *skb){
//---------------------------------------------------------------------------
struct classifier_entity *pclassifier, *sp;
uint8_t *protocolh = NULL;
uint8_t version;
uint8_t protocol, dscp;
uint16_t classref;
struct cx_entity *cx;
unsigned int i;
#ifdef NAS_DEBUG_CLASS
char sfct[10], sprotocol[10];
#endif
struct net_device *dev = gdev;
unsigned char cx_index,no_connection;
int addr_type;
int mbms_ix;
struct in6_addr masked6_addr;
struct in_addr masked_addr;
// RARP vars
struct arphdr *rarp;
unsigned char *rarp_ptr;
/* s for "source", t for "target" */
__be32 sip, tip;
unsigned char *sha, *tha;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_send: begin -\n");
#endif
if (skb==NULL){
printk("nasrg_CLASS_send - input parameter skb is NULL \n");
return;
}
//***
#ifdef NAS_DEBUG_SEND
printk("nasrg_CLASS_send - Received IP packet to transmit, length %d\n", skb->len);
#endif
#ifdef NAS_DEBUG_SEND_DETAIL
if ((skb->data) != NULL){
if (skb->len<150)
nasrg_TOOL_print_buffer(skb->data,skb->len);
else
nasrg_TOOL_print_buffer(skb->data,150);
}
#endif
//***
// find all connections related to socket
cx_index = 0;
no_connection = 1;
cx = NULL;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_send: [before switch on IP protocol version] \n");
#endif
// Get mobile connexion entity, protocol and dscp from IP packet
switch (ntohs(skb->protocol)) {
case ETH_P_IPV6:
#ifdef NAS_DEBUG_CLASS_DETAIL
printk("nasrg_CLASS_send : skb->protocol : IPv6 \n");
#endif
version = NAS_VERSION_6;
addr_type = NAS_IPV6_ADDR_UNKNOWN;
protocolh = nasrg_TOOL_get_protocol6(ipv6_hdr(skb), &protocol);
dscp = nasrg_TOOL_get_dscp6 (ipv6_hdr(skb));
cx = nasrg_CLASS_cx6 (skb, dscp, &addr_type, &cx_index, &mbms_ix);
#ifdef NAS_DEBUG_CLASS_DETAIL
printk("nasrg_CLASS_send - ETH_P_IPV6 skb %p dscp %d gpriv %p cx_index %p \n",skb, dscp, gpriv, &cx_index);
#endif
// find in default DSCP a valid classification
if (cx == NULL) {
switch (addr_type) {
case NAS_IPV6_ADDR_MC_SIGNALLING:
case NAS_IPV6_ADDR_UNICAST:
#ifdef NAS_DEBUG_CLASS_DETAIL
printk("nasrg_CLASS_send - case NAS_IPV6_ADDR_MC_SIGNALLING | NAS_IPV6_ADDR_UNICAST\n");
#endif //NAS_DEBUG_CLASS
for (i=0; i<NAS_CX_MAX; i++){
pclassifier=(&gpriv->cx[i])->sclassifier[NAS_DSCP_DEFAULT];
while (pclassifier!=NULL) {
if ((pclassifier->version == NAS_VERSION_6) || (pclassifier->version == NAS_VERSION_DEFAULT)) {
// ok found default classifier for this packet
nasrg_create_mask_ipv6_addr(&masked6_addr, pclassifier->dplen);
// Modified MW to let everything go (pb with signalling)
masked6_addr.s6_addr32[0] = 0x00000000;
masked6_addr.s6_addr32[1] = 0x00000000;
#ifdef NAS_DEBUG_CLASS_DETAIL
printk("nasrg_CLASS_send - cx %d : DSCP NAS_DSCP_DEFAULT %X:%X:%X:%X:%X:%X:%X:%X\n",i, NIP6ADDR(&(pclassifier->daddr.ipv6)));
#endif //NAS_DEBUG_CLASS
if (IN6_ARE_ADDR_MASKED_EQUAL(&pclassifier->daddr.ipv6, &ipv6_hdr(skb)->daddr, &masked6_addr)) {
// then force dscp
cx = &gpriv->cx[i];
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_send - ETH_P_IPV6 FOUND NAS_DSCP_DEFAULT with IN6_ARE_ADDR_MASKED_EQUAL(%d bits)\n",pclassifier->dplen);
#endif
dscp = NAS_DSCP_DEFAULT;
break;
} else {
if(IN6_IS_ADDR_UNSPECIFIED(&pclassifier->daddr.ipv6)) {
cx = &gpriv->cx[i];
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_send - ETH_P_IPV6 FOUND NAS_DSCP_DEFAULT with IN6_IS_ADDR_UNSPECIFIED\n");
#endif
dscp = NAS_DSCP_DEFAULT;
break;
}
}
}
pclassifier = pclassifier->next;
}
}
break;
// MBMS is broken!!!! To be updated (these values will be over-ridden afterwards
case NAS_IPV6_ADDR_MC_MBMS:
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_send - case NAS_IPV6_ADDR_MC_MBMS\n");
#endif //NAS_DEBUG_CLASS
pclassifier = gpriv->mbmsclassifier[mbms_ix];
printk("nasrg_CLASS_send: MBMS is broken!!!!\n\n\n");
sp = gpriv->mbmsclassifier[mbms_ix];
if (sp!= NULL){
classref=sp->classref;
#ifdef NAS_DEBUG_CLASS_DETAIL
printk("nasrg_CLASS_send: classifier found for multicast service %d \n", mbms_ix);
#endif
}else{
printk("nasrg_CLASS_send: No corresponding multicast bearer, so the message is dropped\n");
return;
}
break;
// should have found a valid classification rule
case NAS_IPV6_ADDR_UNKNOWN:
default:
printk("nasrg_CLASS_send: No corresponding address type\n");
}
}
break;
case ETH_P_ARP:
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_send : skb->protocol : ARP \n");
#endif
version = NAS_VERSION_4;
addr_type = NAS_IPV4_ADDR_BROADCAST;
dscp = 0;
cx = NULL;
// Basic sanity checks can be done without the lock
rarp = (struct arphdr *)skb_network_header(skb);
if (rarp) {
if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)) {
printk("nasrg_CLASS_send: ARP PACKET WRONG ADDR LEN or WRONG ARP HEADER TYPE\n");
break;
}
} else {
printk("nasrg_CLASS_send: ARP HEADER POINTER IS NULL\n");
break;
}
// If it's not Ethernet, delete it.
if (rarp->ar_pro != htons(ETH_P_IP)) {
printk("nasrg_CLASS_send: ARP PACKET PROTOCOL IS NOT ETHERNET\n");
break;
}
rarp_ptr = (unsigned char *) (rarp + 1);
sha = rarp_ptr;
rarp_ptr += dev->addr_len;
memcpy(&sip, rarp_ptr, 4);
rarp_ptr += 4;
tha = rarp_ptr;
rarp_ptr += dev->addr_len;
memcpy(&tip, rarp_ptr, 4);
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_send: ARP DEST IP transport IP = %d.%d.%d.%d\n",NIPADDR(tip));
#endif
for (i=0; i<NAS_CX_MAX; i++){
pclassifier=(&gpriv->cx[i])->sclassifier[NAS_DSCP_DEFAULT];
while (pclassifier!=NULL) {
if ((pclassifier->version == NAS_VERSION_4) || (pclassifier->version == NAS_VERSION_DEFAULT)) {
// ok found default classifier for this packet
nasrg_create_mask_ipv4_addr(&masked_addr, pclassifier->dplen);
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_send: MASK = %d.%d.%d.%d\n",NIPADDR(masked_addr.s_addr));
#endif
//
if (IN_ARE_ADDR_MASKED_EQUAL(&pclassifier->daddr.ipv4, &tip, &masked_addr.s_addr)) {
// then force dscp
cx = &gpriv->cx[i];
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_send: ETH_P_ARP FOUND NAS_DSCP_DEFAULT with IN_ARE_ADDR_MASKED_EQUAL(%d bits)\n", pclassifier->dplen);
#endif
dscp = NAS_DSCP_DEFAULT;
break;
} else {
if (INADDR_ANY == pclassifier->daddr.ipv4) {
cx = &gpriv->cx[i];
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_send: ETH_P_ARP FOUND NAS_DSCP_DEFAULT with INADDR_ANY\n");
#endif
dscp = NAS_DSCP_DEFAULT;
break;
}
}
}
pclassifier = pclassifier->next;
}
}
break;
case ETH_P_IP:
#ifdef NAS_DEBUG_CLASS_DETAIL
printk("nasrg_CLASS_send : skb->protocol : IPv4 \n");
#endif
version = NAS_VERSION_4;
addr_type = NAS_IPV4_ADDR_UNKNOWN;
dscp = nasrg_TOOL_get_dscp4((struct iphdr *)(skb_network_header(skb)));
cx = nasrg_CLASS_cx4(skb, dscp, &addr_type, &cx_index);
protocolh = nasrg_TOOL_get_protocol4((struct iphdr *)(skb_network_header(skb)), &protocol);
// find in default DSCP a valid classification
if (cx == NULL) {
switch (addr_type) {
case NAS_IPV4_ADDR_MC_SIGNALLING:
case NAS_IPV4_ADDR_UNICAST:
case NAS_IPV4_ADDR_BROADCAST:
for (i=0; i<NAS_CX_MAX; i++){
pclassifier=(&gpriv->cx[i])->sclassifier[NAS_DSCP_DEFAULT];
while (pclassifier != NULL) {
if ((pclassifier->version == NAS_VERSION_4) || (pclassifier->version == NAS_VERSION_DEFAULT)) {
// ok found default classifier for this packet
nasrg_create_mask_ipv4_addr(&masked_addr, pclassifier->dplen);
#ifdef NAS_DEBUG_CLASS_DETAIL
printk("nasrg_CLASS_send : MASK = %d.%d.%d.%d\n", NIPADDR(masked_addr.s_addr));
#endif
if (IN_ARE_ADDR_MASKED_EQUAL(&pclassifier->daddr.ipv4, &ip_hdr(skb)->daddr, &masked_addr.s_addr)) {
// then force dscp
cx = &gpriv->cx[i];
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_send : ETH_P_IP FOUND NAS_DSCP_DEFAULT with IN_ARE_ADDR_MASKED_EQUAL(%d bits)\n",pclassifier->dplen);
#endif
dscp = NAS_DSCP_DEFAULT;
break;
} else {
if(INADDR_ANY == pclassifier->daddr.ipv4) {
cx = &gpriv->cx[i];
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_send : ETH_P_IP FOUND NAS_DSCP_DEFAULT with INADDR_ANY\n");
#endif
dscp = NAS_DSCP_DEFAULT;
break;
}
}
}
pclassifier = pclassifier->next;
}
}
break;
// should have found a valid classification rule
case NAS_IPV4_ADDR_UNKNOWN:
default:
printk("nasrg_CLASS_send: No corresponding address type\n");
}
}
#ifdef NAS_DEBUG_CLASS
if (cx)
printk("nasrg_CLASS_send: ETH_P_IP Received IPv4 packet (%02X), dscp = %d, cx = %d\n",ntohs(skb->protocol),dscp,cx->lcr);
else
printk("nasrg_CLASS_send: ETH_P_IP Received IPv4 packet (%02X), dscp = %d, No valid connection\n",ntohs(skb->protocol),dscp);
#endif
break;
default:
printk("nasrg_CLASS_send: Unknown IP version protocol\n");
version = 0;
return;
}
#ifdef NAS_DEBUG_CLASS_DETAIL
printk("nasrg_CLASS_send: [before if (cx != NULL)]\n");
#endif
//Next lines bypass classifiers to test the netlink socket
//#define DEBUG_NETLINKRG_TEST
#ifdef DEBUG_NETLINKRG_TEST
nasrg_COMMON_QOS_send_test_netlink(skb);
return;
#endif
// If a valid connection for the DSCP/EXP with destination address
// is found scan all protocol-based classification rules
if (cx != NULL) {
classref = 0;
sp = NULL;
if (cx->state!=NAS_CX_DCH){
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_send: UE not connected, in state %d. Packet is dropped\n",cx->state);
#endif
return;
}
if (addr_type==NAS_IPV6_ADDR_MC_MBMS){
sp = gpriv->mbmsclassifier[mbms_ix];
if (sp!= NULL){
classref=sp->classref;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_send: classifier found for multicast index %d, service %d\n", mbms_ix, gpriv->mbms_rb[mbms_ix].cnxid);
#endif
}else{
// Temp MEDIEVAL : use default classifier
sp = cx->sclassifier[NAS_DSCP_DEFAULT];
if (sp!= NULL){
classref=sp->classref;
#ifdef NAS_DEBUG_CLASS
printk("nasrg_CLASS_send: classifier for multicast service %d replaced by default %d\n", mbms_ix, classref);
#endif
#ifdef NAS_AUTO_MBMS
nasrg_ASCTL_start_default_mbms_service();
#endif
} else {
printk("nasrg_CLASS_send: No corresponding multicast bearer, so the message is dropped\n");
return;
}
}
}else{
#ifdef NAS_DEBUG_CLASS_DETAIL
printk("nasrg_CLASS_send: DSCP %d version %d: looking for classifier entry\n",dscp, version);
#endif
for (pclassifier=cx->sclassifier[dscp]; pclassifier!=NULL; pclassifier=pclassifier->next) {
#ifdef NAS_DEBUG_CLASS_DETAIL
printk("nasrg_CLASS_send: DSCP %d p->classref=%d,p->protocol=%d,p->version=%d\n",dscp,pclassifier->classref,pclassifier->protocol,pclassifier->version);
#endif
// normal rule checks that network protocol version matches
if ((pclassifier->version == version) || (pclassifier->version == NAS_VERSION_DEFAULT)){
//printk("nasrg_CLASS_send: IP version are equals\n");
sp=pclassifier;
classref=sp->classref;
#ifdef NAS_DEBUG_CLASS_DETAIL
printk("nasrg_CLASS_send: classifier found for dscp %u \n", dscp);
#endif
break;
}
}
}
if (sp!=NULL) {
#ifdef NAS_DEBUG_CLASS
//char sfct[10], sprotocol[10];
// classifier entity found. Print its parameters
if (sp->fct==nasrg_COMMON_QOS_send)
strcpy(sfct, "data xfer");
if (sp->fct==nasrg_CTL_send)
strcpy(sfct, "iocontrol");
if (sp->fct==nasrg_COMMON_del_send)
strcpy(sfct, "delete");
if (sp->fct==nasrg_ASCTL_DC_send_sig_data_request)
strcpy(sfct, "DC-SAP");
switch(protocol) {
case NAS_PROTOCOL_UDP:strcpy(sprotocol, "udp");printk("udp packet\n");break;
case NAS_PROTOCOL_TCP:strcpy(sprotocol, "tcp");printk("tcp packet\n");break;
case NAS_PROTOCOL_ICMP4:strcpy(sprotocol, "icmp4");printk("icmp4 packet\n");break;
case NAS_PROTOCOL_ICMP6:strcpy(sprotocol, "icmp6"); nasrg_TOOL_pk_icmp6((struct icmp6hdr*)protocolh);break;
default:strcpy(sprotocol, "other L4");break;
}
printk("nasrg_CLASS_send: (dscp %u, %s) received, (classref %u, fct %s, drb_id %u) classifier rule\n",
dscp, sprotocol, sp->classref, sfct, sp->rab_id);
#endif
//forward packet to the correct entity
if (sp->fct!=NULL){
sp->fct(skb, cx, sp);
}else{
printk("\n\nnasrg_CLASS_send: ERROR : CLASSIFIER FUNCTION IS NULL\n\n");
}
no_connection = 0;
// end : if classifier entry match found
} else {
printk("nasrg_CLASS_send: no corresponding item in the classifier list, so the message is dropped\n");
printk("nasrg_CLASS_send: packet parameters: dscp %u, %s\n", dscp, sprotocol);
nasrg_COMMON_del_send(skb, cx, NULL); // Note MW: LG has commented this line. Why?
}
} // if connection found
#ifdef NAS_DEBUG_CLASS
if (no_connection == 1) {
printk("nasrg_CLASS_send: no corresponding connection, so the message is dropped\n");
}
#endif
#ifdef NAS_DEBUG_CLASS_DETAIL
printk("nasrg_CLASS_send: end\n");
#endif
}