📄 atm.c
字号:
/* * Cisco 7200 (Predator) simulation platform. * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) * * ATM utility functions and Virtual ATM switch. * * HEC and AAL5 CRC computation functions are from Charles Michael Heard * and can be found at (no licence specified, this is to check!): * * http://cell-relay.indiana.edu/cell-relay/publications/software/CRC/ */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <errno.h>#include <sys/select.h>#include <sys/time.h>#include <sys/types.h>#include "utils.h"#include "registry.h"#include "atm.h"#include "net_io.h"/********************************************************************/#define HEC_GENERATOR 0x107 /* x^8 + x^2 + x + 1 */#define COSET_LEADER 0x055 /* x^6 + x^4 + x^2 + 1 */m_uint8_t hec_syndrome_table[256];/* Generate a table of CRC-8 syndromes for all possible input bytes */static void gen_syndrome_table(void){ int i,j,syndrome; for(i=0;i<256;i++) { syndrome = i; for(j=0;j<8;j++) { if (syndrome & 0x80) syndrome = (syndrome << 1) ^ HEC_GENERATOR; else syndrome = (syndrome << 1); } hec_syndrome_table[i] = (unsigned char)syndrome; }}/* Compute HEC field for ATM header */m_uint8_t atm_compute_hec(m_uint8_t *cell_header){ register m_uint8_t hec_accum = 0; register int i; /* * calculate CRC-8 remainder over first four bytes of cell header. * exclusive-or with coset leader & insert into fifth header byte. */ for(i=0;i<4;i++) hec_accum = hec_syndrome_table[hec_accum ^ cell_header[i]]; return(hec_accum ^ COSET_LEADER);}/* Insert HEC field into an ATM header */void atm_insert_hec(m_uint8_t *cell_header){ cell_header[4] = atm_compute_hec(cell_header);}/* Initialize ATM code (for HEC checksums) */void atm_init(void){ gen_syndrome_table();}/* VPC hash function */static inline u_int atmsw_vpc_hash(u_int vpi){ return((vpi ^ (vpi >> 8)) & (ATMSW_VP_HASH_SIZE-1));}/* VCC hash function */static inline u_int atmsw_vcc_hash(u_int vpi,u_int vci){ return((vpi ^ vci) & (ATMSW_VC_HASH_SIZE-1));}/* VP lookup */atmsw_vp_conn_t *atmsw_vp_lookup(atmsw_table_t *t,netio_desc_t *input, u_int vpi){ atmsw_vp_conn_t *swc; for(swc=t->vp_table[atmsw_vpc_hash(vpi)];swc;swc=swc->next) if ((swc->input == input) && (swc->vpi_in == vpi)) return swc; return NULL;}/* VC lookup */atmsw_vc_conn_t *atmsw_vc_lookup(atmsw_table_t *t,netio_desc_t *input, u_int vpi,u_int vci){ atmsw_vc_conn_t *swc; for(swc=t->vc_table[atmsw_vcc_hash(vpi,vci)];swc;swc=swc->next) if ((swc->input == input) && (swc->vpi_in == vpi) && (swc->vci_in == vci)) return swc; return NULL;}/* VP switching */void atmsw_vp_switch(atmsw_vp_conn_t *vpc,m_uint8_t *cell){ m_uint32_t atm_hdr; /* rewrite the atm header with new vpi */ atm_hdr = ntohl(*(m_uint32_t *)cell); atm_hdr = atm_hdr & ~ATM_HDR_VPI_MASK; atm_hdr |= vpc->vpi_out << ATM_HDR_VPI_SHIFT; *(m_uint32_t *)cell = htonl(atm_hdr); /* recompute HEC field */ atm_insert_hec(cell); /* update the statistics counter */ vpc->cell_cnt++;}/* VC switching */void atmsw_vc_switch(atmsw_vc_conn_t *vcc,m_uint8_t *cell){ m_uint32_t atm_hdr; /* rewrite the atm header with new vpi/vci */ atm_hdr = ntohl(*(m_uint32_t *)cell); atm_hdr = atm_hdr & ~(ATM_HDR_VPI_MASK|ATM_HDR_VCI_MASK); atm_hdr |= vcc->vpi_out << ATM_HDR_VPI_SHIFT; atm_hdr |= vcc->vci_out << ATM_HDR_VCI_SHIFT; *(m_uint32_t *)cell = htonl(atm_hdr); /* recompute HEC field */ atm_insert_hec(cell); /* update the statistics counter */ vcc->cell_cnt++;}/* Handle an ATM cell */ssize_t atmsw_handle_cell(atmsw_table_t *t,netio_desc_t *input, m_uint8_t *cell){ m_uint32_t atm_hdr,vpi,vci; netio_desc_t *output = NULL; atmsw_vp_conn_t *vpc; atmsw_vc_conn_t *vcc; ssize_t len; /* Extract VPI/VCI information */ atm_hdr = ntohl(*(m_uint32_t *)cell); vpi = (atm_hdr & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT; vci = (atm_hdr & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT; /* VP switching */ if ((vpc = atmsw_vp_lookup(t,input,vpi)) != NULL) { atmsw_vp_switch(vpc,cell); output = vpc->output; } else { /* VC switching */ if ((vcc = atmsw_vc_lookup(t,input,vpi,vci)) != NULL) { atmsw_vc_switch(vcc,cell); output = vcc->output; } } len = netio_send(output,cell,ATM_CELL_SIZE); if (len != ATM_CELL_SIZE) { t->cell_drop++; return(-1); } return(0);}/* Receive an ATM cell */static int atmsw_recv_cell(netio_desc_t *nio,u_char *atm_cell,ssize_t cell_len, atmsw_table_t *t){ int res; if (cell_len != ATM_CELL_SIZE) return(-1); ATMSW_LOCK(t); res = atmsw_handle_cell(t,nio,atm_cell); ATMSW_UNLOCK(t); return(res);}/* Acquire a reference to an ATM switch (increment reference count) */atmsw_table_t *atmsw_acquire(char *name){ return(registry_find(name,OBJ_TYPE_ATMSW));}/* Release an ATM switch (decrement reference count) */int atmsw_release(char *name){ return(registry_unref(name,OBJ_TYPE_ATMSW));}/* Create a virtual switch table */atmsw_table_t *atmsw_create_table(char *name){ atmsw_table_t *t; /* Allocate a new switch structure */ if (!(t = malloc(sizeof(*t)))) return NULL; memset(t,0,sizeof(*t)); pthread_mutex_init(&t->lock,NULL); mp_create_fixed_pool(&t->mp,"ATM Switch"); if (!(t->name = mp_strdup(&t->mp,name))) goto err_name; /* Record this object in registry */ if (registry_add(t->name,OBJ_TYPE_ATMSW,t) == -1) { fprintf(stderr,"atmsw_create_table: unable to create switch '%s'\n", name); goto err_reg; } return t; err_reg: err_name: mp_free_pool(&t->mp); free(t); return NULL;}/* Free resources used by a VPC */static void atmsw_release_vpc(atmsw_vp_conn_t *swc){ if (swc) { /* release input NIO */ if (swc->input) { netio_rxl_remove(swc->input); netio_release(swc->input->name); } /* release output NIO */ if (swc->output) netio_release(swc->output->name); }}/* Free resources used by a VCC */static void atmsw_release_vcc(atmsw_vc_conn_t *swc){ if (swc) { /* release input NIO */ if (swc->input) { netio_rxl_remove(swc->input); netio_release(swc->input->name); } /* release output NIO */ if (swc->output) netio_release(swc->output->name); }}/* Create a VP switch connection */int atmsw_create_vpc(atmsw_table_t *t,char *nio_input,u_int vpi_in, char *nio_output,u_int vpi_out){ atmsw_vp_conn_t *swc; u_int hbucket; ATMSW_LOCK(t); /* Allocate a new switch connection */ if (!(swc = mp_alloc(&t->mp,sizeof(*swc)))) { ATMSW_UNLOCK(t); return(-1); } swc->input = netio_acquire(nio_input); swc->output = netio_acquire(nio_output); swc->vpi_in = vpi_in; swc->vpi_out = vpi_out; /* Check these NIOs are valid and the input VPI does not exists */ if (!swc->input || !swc->output || atmsw_vp_lookup(t,swc->input,vpi_in)) goto error; /* Add as a RX listener */ if (netio_rxl_add(swc->input,(netio_rx_handler_t)atmsw_recv_cell, t,NULL) == -1) goto error; hbucket = atmsw_vpc_hash(vpi_in); swc->next = t->vp_table[hbucket]; t->vp_table[hbucket] = swc; ATMSW_UNLOCK(t); return(0); error: ATMSW_UNLOCK(t); atmsw_release_vpc(swc); mp_free(swc); return(-1);}/* Delete a VP switch connection */int atmsw_delete_vpc(atmsw_table_t *t,char *nio_input,u_int vpi_in, char *nio_output,u_int vpi_out){ netio_desc_t *input,*output; atmsw_vp_conn_t **swc,*p; u_int hbucket; ATMSW_LOCK(t); input = registry_exists(nio_input,OBJ_TYPE_NIO); output = registry_exists(nio_output,OBJ_TYPE_NIO); if (!input || !output) { ATMSW_UNLOCK(t); return(-1); } hbucket = atmsw_vpc_hash(vpi_in); for(swc=&t->vp_table[hbucket];*swc;swc=&(*swc)->next) { p = *swc;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -