/* * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under * the OAI Public License, Version 1.0 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * * http://www.openairinterface.org/?page_id=698 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org */ /*! \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 #include #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; dscpisclassifier[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; dscpirclassifier[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; mbmsimbmsclassifier[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; cxicx[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; cxicx+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; cxicx[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; icx[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; icx[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; icx[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 }