diff -ur --new-file old/linux/include/linux/atmmpc.h new/linux/include/linux/atmmpc.h --- old/linux/include/linux/atmmpc.h Wed Aug 19 20:46:45 1998 +++ new/linux/include/linux/atmmpc.h Wed Aug 19 20:47:28 1998 @@ -22,7 +22,6 @@ uint8_t eg_MPC_ATM_addr[ATM_ESA_LEN]; uint32_t tag; uint32_t in_dst_ip; /* IP address this ingress MPC sends packets to */ - uint32_t service_category; uint16_t holding_time; uint32_t request_id; } in_ctrl_info; @@ -45,6 +44,7 @@ in_ctrl_info in_info; eg_ctrl_info eg_info; } content; + struct atm_qos qos; /* only used with content.in_info */ } k_message; struct llc_snap_hdr { /* RFC 1483 LLC/SNAP encapsulation for routed IP PDUs */ diff -ur --new-file old/linux/net/atm/mpc.c new/linux/net/atm/mpc.c --- old/linux/net/atm/mpc.c Wed Aug 19 20:46:46 1998 +++ new/linux/net/atm/mpc.c Wed Aug 19 20:47:29 1998 @@ -100,6 +100,7 @@ #endif struct mpoa_client *mpcs = NULL; /* FIXME */ +static struct atm_mpoa_qos *qos_head = NULL; static struct timer_list mpc_timer; @@ -145,6 +146,100 @@ return NULL; /* not found */ } +/* + * Functions for managing QoS list + */ + +/* + * Returns the new entry. Note the use of the 2nd argument + */ +struct atm_mpoa_qos *atm_mpoa_add_qos(uint32_t dst_ip, struct atm_qos *qos) +{ + struct atm_mpoa_qos *entry; + + entry = kmalloc(sizeof(struct atm_qos), GFP_KERNEL); + if (entry == NULL) { + printk("mpoa: atm_mpoa_add_qos: out of memory\n"); + return entry; + } + + entry->ipaddr = dst_ip; + entry->qos = *qos; + + entry->next = qos_head; + qos_head = entry; + + return entry; +} + +struct atm_mpoa_qos *atm_mpoa_search_qos(uint32_t dst_ip) +{ + struct atm_mpoa_qos *qos; + + qos = qos_head; + while( qos != NULL ){ + if(qos->ipaddr == dst_ip) { + break; + } + qos = qos->next; + } + + return qos; +} + +/* + * Returns 0 for failure + */ +int atm_mpoa_delete_qos(struct atm_mpoa_qos *entry) +{ + + struct atm_mpoa_qos *curr; + + if (entry == NULL) return 0; + if (entry == qos_head) { + qos_head = qos_head->next; + kfree(qos_head); + return 1; + } + + curr = qos_head; + while (curr != NULL) { + if (curr->next == entry) { + curr->next = entry->next; + kfree(entry); + return 1; + } + curr = curr->next; + } + + return 0; +} + +void atm_mpoa_disp_qos(char *page, int *len) +{ + + unsigned char *ip; + char ipaddr[16]; + struct atm_mpoa_qos *qos; + + qos = qos_head; + *len += sprintf(page + *len, "QoS entries for shortcuts:\n"); + *len += sprintf(page + *len, "IP address TX:max_pcr pcr min_pcr max_cdv max_sdu RX:max_pcr pcr min_pcr max_cdv max_sdu\n"); + + ipaddr[sizeof(ipaddr)-1] = '\0'; + while (qos != NULL) { + ip = (unsigned char *)&qos->ipaddr; + sprintf(ipaddr, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + *len += sprintf(page + *len, "%-16s %-7d %-7d %-7d %-7d %-7d %-7d %-7d %-7d %-7d %-7d\n", + ipaddr, + qos->qos.txtp.max_pcr, qos->qos.txtp.pcr, qos->qos.txtp.min_pcr, qos->qos.txtp.max_cdv, qos->qos.txtp.max_sdu, + qos->qos.rxtp.max_pcr, qos->qos.rxtp.pcr, qos->qos.rxtp.min_pcr, qos->qos.rxtp.max_cdv, qos->qos.rxtp.max_sdu); + qos = qos->next; + } + + return; +} + static struct device *find_lec_by_itfnum(int itf) { extern struct atm_lane_ops atm_lane_ops; /* in common.c */ @@ -163,7 +258,7 @@ if (mpc == NULL) return NULL; memset(mpc, 0, sizeof(struct mpoa_client)); -#if 0 +#if 0 /* compiler seems to barf on this */ mpc->ingress_lock = RW_LOCK_UNLOCKED; mpc->egress_lock = RW_LOCK_UNLOCKED; #endif @@ -597,6 +692,7 @@ return; } + eg->latest_ip_addr = ((struct iphdr *)new_skb->data)->saddr; eg->packets_rcvd++; netif_rx(new_skb); @@ -922,15 +1018,20 @@ static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *client) { + unsigned char *ip; + struct atm_mpoa_qos *qos; uint32_t dst_ip = msg->content.in_info.in_dst_ip; in_cache_entry *entry = client->in_ops->search(dst_ip, client); + eg_cache_entry *eg_entry; - dprintk("mpoa: (%s) MPOA_res_reply_rcvd() entry = %p", client->dev->name, entry); + ip = (unsigned char *)&dst_ip; + dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %d.%d.%d.%d\n", client->dev->name, ip[0], ip[1], ip[2], ip[3]); + ddprintk("mpoa: (%s) MPOA_res_reply_rcvd() entry = %p", client->dev->name, entry); if(entry == NULL){ printk("\nmpoa: (%s): ARGH, received res. reply for an entry that doesn't exist.\n", client->dev->name); return; } - printk(" entry_state = %d ", entry->entry_state); + ddprintk(" entry_state = %d ", entry->entry_state); if (entry->entry_state == INGRESS_RESOLVED) { printk("\nmpoa: (%s) MPOA_res_reply_rcvd for RESOLVED entry!\n", client->dev->name); @@ -941,21 +1042,47 @@ do_gettimeofday(&(entry->tv)); do_gettimeofday(&(entry->reply_wait)); /* Used in refreshing func from now on */ entry->refresh_time = 0; - printk("entry->shortcut = %p\n", entry->shortcut); + ddprintk("entry->shortcut = %p\n", entry->shortcut); if(entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL){ entry->entry_state = INGRESS_RESOLVED; - return; /* Shortcut already open... */ + return; /* Shortcut already open... */ } - if (entry->shortcut == NULL) { - entry->entry_state = INGRESS_RESOLVED; - msg->type = OPEN_INGRESS_SVC; - msg_to_mpoad(msg,client); - return; - } - printk("mpoa: (%s) MPOA_res_reply_rcvd: still here, impossible!\n", client->dev->name); - return; + if (entry->shortcut != NULL) { + printk("mpoa: (%s) MPOA_res_reply_rcvd: entry->shortcut != NULL, impossible!\n", + client->dev->name); + return; + } + + /* entry->shortcut == NULL so we need to get a VC. First check for candicates + * in egress cache. If none found, ask daemon to create one. + */ + eg_entry = client->eg_ops->search_by_src_ip(dst_ip, client); + if (eg_entry != NULL) { + ip = (unsigned char *)&dst_ip; + entry->shortcut = eg_entry->shortcut; + dprintk("mpoa: (%s) using egress SVC to reach %d.%d.%d.%d\n", + client->dev->name, ip[0], ip[1], ip[2], ip[3]); + + } + + /* It is possible that there was an egress entry with no valid shortcut */ + if (entry->shortcut == NULL) { + msg->type = OPEN_INGRESS_SVC; + qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); + if (qos != NULL) { + msg->qos = qos->qos; + printk("mpoa: (%s) MPOA_res_reply_rcvd: trying to get a CBR shortcut\n", + client->dev->name); + } + msg_to_mpoad(msg, client); + } + + entry->entry_state = INGRESS_RESOLVED; + + return; + } static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) @@ -1226,6 +1353,7 @@ { extern struct atm_mpoa_ops atm_mpoa_ops; struct mpoa_client *mpc, *tmp; + struct atm_mpoa_qos *qos, *nextqos; struct lec_priv *priv; if (MOD_IN_USE) { @@ -1259,9 +1387,17 @@ memset(mpc, 0, sizeof(struct mpoa_client)); ddprintk("mpoa: cleanup_module: about to kfree %p\n", mpc); kfree(mpc); - ddprintk("mpoa: cleanup_module: kfree() done\n"); ddprintk("mpoa: cleanup_module: next mpc is at %p\n", tmp); mpc = tmp; + } + + qos = qos_head; + qos_head = NULL; + while (qos != NULL) { + nextqos = qos->next; + dprintk("mpoa: cleanup_module: freeing qos entry %p\n", qos); + kfree(qos); + qos = nextqos; } return; diff -ur --new-file old/linux/net/atm/mpc.h new/linux/net/atm/mpc.h --- old/linux/net/atm/mpc.h Wed Aug 19 20:46:46 1998 +++ new/linux/net/atm/mpc.h Wed Aug 19 20:47:29 1998 @@ -1,6 +1,7 @@ #ifndef _MPC_H_ #define _MPC_H_ +#include <linux/atm.h> #include <linux/atmmpc.h> #include <linux/skbuff.h> #include <asm/spinlock.h> @@ -16,23 +17,29 @@ struct mpoa_client { struct mpoa_client *next; - struct device *dev; /* lec in question */ - int dev_num; /* e.g. 2 for lec2 */ + struct device *dev; /* lec in question */ + int dev_num; /* e.g. 2 for lec2 */ int (*old_hard_start_xmit)(struct sk_buff *skb, struct device *dev); - struct atm_vcc *mpoad_vcc; /* control channel to mpoad */ - uint8_t mps_ctrl_addr[ATM_ESA_LEN]; /* MPS control ATM address */ - uint8_t our_ctrl_addr[ATM_ESA_LEN]; /* MPC's control ATM address */ + struct atm_vcc *mpoad_vcc; /* control channel to mpoad */ + uint8_t mps_ctrl_addr[ATM_ESA_LEN]; /* MPS control ATM address */ + uint8_t our_ctrl_addr[ATM_ESA_LEN]; /* MPC's control ATM address */ rwlock_t ingress_lock; - struct in_cache_ops *in_ops; /* ingress cache operations */ - in_cache_entry *in_cache; /* the ingress cache of this MPC */ + struct in_cache_ops *in_ops; /* ingress cache operations */ + in_cache_entry *in_cache; /* the ingress cache of this MPC */ rwlock_t egress_lock; - struct eg_cache_ops *eg_ops; /* egress cache operations */ - eg_cache_entry *eg_cache; /* the egress cache of this MPC */ + struct eg_cache_ops *eg_ops; /* egress cache operations */ + eg_cache_entry *eg_cache; /* the egress cache of this MPC */ - uint8_t *mps_macs; /* array of MPS MAC addresses, >=1 */ - int number_of_mps_macs; /* number of the above MAC addresses */ + uint8_t *mps_macs; /* array of MPS MAC addresses, >=1 */ + int number_of_mps_macs; /* number of the above MAC addresses */ +}; + +struct atm_mpoa_qos { + struct atm_mpoa_qos *next; + uint32_t ipaddr; + struct atm_qos qos; }; /* TLVs this MPC recognizes */ @@ -55,5 +62,12 @@ void atm_mpoa_init(void); void atm_mpoa_init_ops(struct atm_mpoa_ops *ops); -#endif /* _MPC_H_ */ +/* MPOA QoS operations */ +struct atm_mpoa_qos *atm_mpoa_add_qos(uint32_t dst_ip, struct atm_qos *qos); +struct atm_mpoa_qos *atm_mpoa_search_qos(uint32_t dst_ip); +int atm_mpoa_delete_qos(struct atm_mpoa_qos *qos); +/* Display QoS entries. This is for the procfs */ +void atm_mpoa_disp_qos(char *page, int *len); + +#endif /* _MPC_H_ */ diff -ur --new-file old/linux/net/atm/mpoa_caches.c new/linux/net/atm/mpoa_caches.c --- old/linux/net/atm/mpoa_caches.c Wed Aug 19 20:46:46 1998 +++ new/linux/net/atm/mpoa_caches.c Wed Aug 19 20:47:29 1998 @@ -100,6 +100,7 @@ static int cache_hit( in_cache_entry * entry, struct mpoa_client *mpc) { + struct atm_mpoa_qos *qos; struct k_message msg; entry->count++; @@ -111,6 +112,8 @@ msg.type = SND_MPOA_RES_RTRY; msg.content.in_info = entry->ctrl_info; memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN); + qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); + if (qos != NULL) msg.qos = qos->qos; msg_to_mpoad(&msg, mpc); do_gettimeofday(&(entry->reply_wait)); entry->entry_state = INGRESS_RESOLVING; @@ -132,6 +135,8 @@ msg.type = SND_MPOA_RES_RQST; memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN ); msg.content.in_info = entry->ctrl_info; + qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); + if (qos != NULL) msg.qos = qos->qos; msg_to_mpoad( &msg, mpc); do_gettimeofday(&(entry->reply_wait)); } @@ -228,6 +233,7 @@ static void check_resolving_entries( struct mpoa_client * client ) { + struct atm_mpoa_qos *qos; unsigned long flags; in_cache_entry *entry; struct timeval now; @@ -258,7 +264,9 @@ msg.type = SND_MPOA_RES_RTRY; memcpy(msg.MPS_ctrl, client->mps_ctrl_addr, ATM_ESA_LEN); msg.content.in_info = entry->ctrl_info; - msg_to_mpoad(&msg, client ); + qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); + if (qos != NULL) msg.qos = qos->qos; + msg_to_mpoad(&msg, client); do_gettimeofday(&(entry->reply_wait)); } } @@ -354,6 +362,25 @@ return NULL; } +static eg_cache_entry *eg_cache_search_by_src_ip(uint32_t ipaddr, + struct mpoa_client *client) +{ + unsigned long flags; + eg_cache_entry *entry; + + read_lock_irqsave(&client->egress_lock, flags); + entry = client->eg_cache; + while( entry != NULL ){ + if(entry->latest_ip_addr == ipaddr) { + break; + } + entry = entry->next; + } + read_unlock_irqrestore(&client->egress_lock, flags); + + return entry; +} + /* * If there are no more references to vcc in ingress cache, * we are ready to close it. @@ -464,7 +491,7 @@ msg.type = SND_EGRESS_PURGE; msg.content.eg_info = entry->ctrl_info; printk("mpoa: mpoa_caches.c: egress_cache:holding time expired, cache_id = %lu.\n",ntohl(entry->ctrl_info.cache_id)); - msg_to_mpoad(&msg,client); + msg_to_mpoad(&msg, client); eg_cache_remove(entry, client); } entry = next_entry; @@ -484,7 +511,7 @@ in_cache_remove, /* cache_remove */ clear_count_and_expired, /* clear_count */ check_resolving_entries, /* check_resolving */ - refresh_entries /* refresh */ + refresh_entries, /* refresh */ }; static struct eg_cache_ops egress_ops = { @@ -492,6 +519,7 @@ eg_cache_search_by_cache_id, /* search_by_cache_id */ eg_cache_search_by_tag, /* search_by_tag */ eg_cache_search_by_vcc, /* search_by_vcc */ + eg_cache_search_by_src_ip, /* search_by_src_ip */ eg_cache_remove, /* cache_remove */ update_eg_cache_entry, /* update */ clear_expired /* clear_expired */ diff -ur --new-file old/linux/net/atm/mpoa_caches.h new/linux/net/atm/mpoa_caches.h --- old/linux/net/atm/mpoa_caches.h Wed Aug 19 20:46:46 1998 +++ new/linux/net/atm/mpoa_caches.h Wed Aug 19 20:47:29 1998 @@ -7,8 +7,6 @@ #include <linux/atmdev.h> #include <linux/atmmpc.h> - - struct mpoa_client; void atm_mpoa_init_cache(struct mpoa_client *mpc); @@ -52,6 +50,7 @@ struct atm_vcc *shortcut; uint32_t packets_rcvd; uint16_t entry_state; + uint32_t latest_ip_addr; /* The src IP address of the last packet */ struct eg_ctrl_info ctrl_info; } eg_cache_entry; @@ -60,6 +59,7 @@ eg_cache_entry *(*search_by_cache_id)(uint32_t cache_id, struct mpoa_client *client); eg_cache_entry *(*search_by_tag)(uint32_t cache_id, struct mpoa_client *client); eg_cache_entry *(*search_by_vcc)(struct atm_vcc *vcc, struct mpoa_client *client); + eg_cache_entry *(*search_by_src_ip)(uint32_t ipaddr, struct mpoa_client *client); int (*cache_remove)(eg_cache_entry *entry, struct mpoa_client *client); void (*update)(eg_cache_entry *entry, uint16_t holding_time); void (*clear_expired)(struct mpoa_client *client); diff -ur --new-file old/linux/net/atm/mpoa_proc.c new/linux/net/atm/mpoa_proc.c --- old/linux/net/atm/mpoa_proc.c Wed Aug 19 20:46:46 1998 +++ new/linux/net/atm/mpoa_proc.c Wed Aug 19 20:47:29 1998 @@ -9,6 +9,7 @@ #include <linux/time.h> #include <asm/uaccess.h> #include <linux/atmmpc.h> +#include <linux/atm.h> #include "mpc.h" #include "mpoa_caches.h" @@ -17,6 +18,12 @@ * file system statistics */ +#if 1 +#define dprintk printk /* debug */ +#else +#define dprintk(format,args...) +#endif + #define STAT_FILE_NAME "mpc" /* Our statistic file's name */ extern struct mpoa_client *mpcs; @@ -25,13 +32,18 @@ static ssize_t proc_mpc_read(struct file *file, char *buff, size_t count, loff_t *pos); +static ssize_t proc_mpc_write(struct file *file, const char *buff, + size_t nbytes, loff_t *ppos); + +static int parse_qos(const char *buff, int len); + /* * Define allowed FILE OPERATIONS */ static struct file_operations mpc_file_operations = { NULL, /* lseek */ proc_mpc_read, /* read */ - NULL, /* write */ + proc_mpc_write, /* write */ NULL, /* readdir */ NULL, /* poll - default */ NULL, /* ioctl - default */ @@ -150,7 +162,8 @@ return 0; page = get_free_page(GFP_KERNEL); if(!page) - return -ENOMEM; + return -ENOMEM; + atm_mpoa_disp_qos((char *)page, &length); while(mpc != NULL){ length += print_header((char *)page + length, mpc); length += sprintf((char *)page + length,"Ingress Entries:\nIP-address State Holding_time Packets_fwded VPI VCI\n"); @@ -166,13 +179,19 @@ } length += sprintf((char *)page + length,"\n"); eg_entry = mpc->eg_cache; - length += sprintf((char *)page + length,"Egress Entries:\nIngress_MPC_ATM_addr\nCache_id State Holding_time Packets_recvd VPI VCI\n"); + length += sprintf((char *)page + length,"Egress Entries:\nIngress_MPC_ATM_addr\nCache_id State Holding_time Packets_recvd Latest IP addr VPI VCI\n"); while(eg_entry != NULL){ for(i=0;i<ATM_ESA_LEN;i++){ length += sprintf((char *)page + length,"%02x",eg_entry->ctrl_info.in_MPC_data_ATM_addr[i]);} - length += sprintf((char *)page + length,"\n%-16lu%s%-14lu%-12u",ntohl(eg_entry->ctrl_info.cache_id), egress_state_string(eg_entry->entry_state), (eg_entry->ctrl_info.holding_time-(now.tv_sec-eg_entry->tv.tv_sec)), eg_entry->packets_rcvd); + length += sprintf((char *)page + length,"\n%-16lu%s%-14lu%-15u",ntohl(eg_entry->ctrl_info.cache_id), egress_state_string(eg_entry->entry_state), (eg_entry->ctrl_info.holding_time-(now.tv_sec-eg_entry->tv.tv_sec)), eg_entry->packets_rcvd); + + /* latest IP address */ + temp = (unsigned char *)&eg_entry->latest_ip_addr; + sprintf(ip_string, "%d.%d.%d.%d", temp[0], temp[1], temp[2], temp[3]); + length += sprintf((char *)page + length, "%-16s", ip_string); + if(eg_entry->shortcut) - length += sprintf((char *)page + length," %-3d %-3d",eg_entry->shortcut->vpi,eg_entry->shortcut->vci); + length += sprintf((char *)page + length," %-3d %-3d",eg_entry->shortcut->vpi,eg_entry->shortcut->vci); length += sprintf((char *)page + length,"\n"); eg_entry = eg_entry->next; } @@ -189,6 +208,157 @@ free_page(page); return length; +} + +static ssize_t proc_mpc_write(struct file *file, const char *buff, + size_t nbytes, loff_t *ppos) +{ + int incoming, error, retval; + char *page, c; + const char *tmp; + + if (nbytes < 0) return -EINVAL; + if (nbytes == 0) return 0; + if (nbytes > PAGE_SIZE) nbytes = PAGE_SIZE-1; + + error = verify_area(VERIFY_READ, buff, nbytes); + if (error) return error; + + page = (char *)__get_free_page(GFP_KERNEL); + if (page == NULL) return -ENOMEM; + + incoming = 0; + tmp = buff; + while(incoming < nbytes){ + if (get_user(c, tmp++)) return -EFAULT; + incoming++; + if (c == '\0' || c == '\n') + break; + } + + retval = copy_from_user(page, buff, incoming); + if (retval != 0) { + printk("mpoa: proc_mpc_write: copy_from_user() failed\n"); + return -EFAULT; + } + + *ppos += incoming; + + page[incoming] = '\0'; + retval = parse_qos(buff, incoming); + if (retval == 0) + printk("mpoa: proc_mpc_write: could not parse '%s'\n", page); + + free_page((unsigned long)page); + + return nbytes; +} + +static int parse_qos(const char *buff, int len) +{ + /* possible lines look like this + * add 130.230.54.142 tx=max_pcr,pcr,min_pcr,max_cdv,max_sdu rx=max_pcr,pcr,min_pcr,max_cdv,max_sd + */ + + int pos, i; + uint32_t ipaddr; + unsigned char ip[4]; + char cmd[4], temp[256]; + const char *tmp, *prev; + struct atm_qos qos; + int value[5]; + + pos = 0; + strncpy(cmd, buff, 3); + if( strncmp(cmd,"add", 3) && strncmp(cmd,"del", 3)) + return 0; /* not add or del */ + + pos += 4; + /* next parse ip */ + prev = buff + pos; + for (i = 0; i < 3; i++) { + tmp = strchr(prev, '.'); + if (tmp == NULL) return 0; + memset(temp, '\0', 256); + memcpy(temp, prev, tmp-prev); + ip[i] = (char)simple_strtoul(temp, NULL, 0); + tmp ++; + prev = tmp; + } + tmp = strchr(prev, ' '); + if (tmp == NULL) return 0; + memset(temp, '\0', 256); + memcpy(temp, prev, tmp-prev); + ip[i] = (char)simple_strtoul(temp, NULL, 0); + ipaddr = *(uint32_t *)ip; + + if(!strncmp(cmd, "del", 3)) + return atm_mpoa_delete_qos(atm_mpoa_search_qos(ipaddr)); + tmp = strstr(buff, "tx="); + if(tmp == NULL) return 0; + tmp += 3; + prev = tmp; + for( i = 0; i < 4; i++){ + tmp = strchr(prev, ','); + if (tmp == NULL) return 0; + memset(temp, '\0', 256); + memcpy(temp, prev, tmp-prev); + value[i] = (int)simple_strtoul(temp, NULL, 0); + tmp ++; + prev = tmp; + } + tmp = strchr(prev, ' '); + if (tmp == NULL) return 0; + memset(temp, '\0', 256); + memcpy(temp, prev, tmp-prev); + value[i] = (int)simple_strtoul(temp, NULL, 0); + qos.txtp.traffic_class = ATM_CBR; + qos.txtp.max_pcr = value[0]; + qos.txtp.pcr = value[1]; + qos.txtp.min_pcr = value[2]; + qos.txtp.max_cdv = value[3]; + qos.txtp.max_sdu = value[4]; + + tmp = strstr(buff, "rx="); + if(tmp == NULL) return 0; + tmp += 3; + prev = tmp; + for( i = 0; i < 4; i++){ + tmp = strchr(prev, ','); + if (tmp == NULL) return 0; + memset(temp, '\0', 256); + memcpy(temp, prev, tmp-prev); + value[i] = (int)simple_strtoul(temp, NULL, 0); + tmp ++; + prev = tmp; + } + tmp = strchr(prev, '\0'); + if (tmp == NULL) return 0; + memset(temp, '\0', 256); + memcpy(temp, prev, tmp-prev); + value[i] = (int)simple_strtoul(temp, NULL, 0); + qos.rxtp.traffic_class = ATM_CBR; + qos.rxtp.max_pcr = value[0]; + qos.rxtp.pcr = value[1]; + qos.rxtp.min_pcr = value[2]; + qos.rxtp.max_cdv = value[3]; + qos.rxtp.max_sdu = value[4]; + dprintk("mpoa: mpoa_proc.c: parse_qos(): setting qos paramameters to tx=%d,%d,%d,%d,%d rx=%d,%d,%d,%d,%d\n", + qos.txtp.max_pcr, + qos.txtp.pcr, + qos.txtp.min_pcr, + qos.txtp.max_cdv, + qos.txtp.max_sdu, + qos.rxtp.max_pcr, + qos.rxtp.pcr, + qos.rxtp.min_pcr, + qos.rxtp.max_cdv, + qos.rxtp.max_sdu + ); + + qos.aal = ATM_AAL5; + atm_mpoa_add_qos(ipaddr, &qos); + return 1; } /*