sdla_fr.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:148k
- return 0;
- }
- /* Set the WNodeID to our network address */
- sendpacket[43] = (unsigned char)(network_number >> 24);
- sendpacket[44] = (unsigned char)((network_number & 0x00FF0000) >> 16);
- sendpacket[45] = (unsigned char)((network_number & 0x0000FF00) >> 8);
- sendpacket[46] = (unsigned char)(network_number & 0x000000FF);
- return 1;
- }
- /* If we get here, its an IPX-data packet so it'll get passed up the
- * stack.
- * switch the network numbers
- */
- switch_net_numbers(sendpacket, network_number ,1);
- return 0;
- }
- /*============================================================================
- * process_route
- *
- * Rationale:
- * If the interface goes down, or we receive an ARP request,
- * we have to change the network interface ip addresses.
- * This cannot be done within the interrupt.
- *
- * Description:
- *
- * This routine is called as a polling routine to dynamically
- * add/delete routes negotiated by inverse ARP. It is in this
- * "task" because we don't want routes to be added while in
- * interrupt context.
- *
- * Usage:
- * This function is called by fr_poll() polling funtion.
- */
- static void process_route (netdevice_t *dev)
- {
- fr_channel_t *chan = dev->priv;
- sdla_t *card = chan->card;
- #if defined(LINUX_2_1) || defined(LINUX_2_4)
- struct ifreq if_info;
- struct sockaddr_in *if_data;
- mm_segment_t fs = get_fs();
- u32 ip_tmp;
- int err;
- switch(chan->route_flag){
- case ADD_ROUTE:
-
- /* Set remote addresses */
- memset(&if_info, 0, sizeof(if_info));
- strcpy(if_info.ifr_name, dev->name);
- set_fs(get_ds()); /* get user space block */
-
- if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr;
- if_data->sin_addr.s_addr = chan->ip_remote;
- if_data->sin_family = AF_INET;
- err = devinet_ioctl( SIOCSIFDSTADDR, &if_info );
- set_fs(fs); /* restore old block */
- if (err) {
- printk(KERN_INFO
- "%s: Route Add failed. Error: %dn",
- card->devname,err);
- printk(KERN_INFO "%s: Address: %sn",
- chan->name, in_ntoa(chan->ip_remote));
- }else {
- printk(KERN_INFO "%s: Route Added Successfully: %sn",
- card->devname,in_ntoa(chan->ip_remote));
- chan->route_flag = ROUTE_ADDED;
- }
- break;
- case REMOVE_ROUTE:
- /* Set remote addresses */
- memset(&if_info, 0, sizeof(if_info));
- strcpy(if_info.ifr_name, dev->name);
- ip_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP);
- set_fs(get_ds()); /* get user space block */
-
- if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr;
- if_data->sin_addr.s_addr = 0;
- if_data->sin_family = AF_INET;
- err = devinet_ioctl( SIOCSIFDSTADDR, &if_info );
- set_fs(fs);
-
- if (err) {
- printk(KERN_INFO
- "%s: Deleting of route failed. Error: %dn",
- card->devname,err);
- printk(KERN_INFO "%s: Address: %sn",
- dev->name,in_ntoa(chan->ip_remote) );
- } else {
- printk(KERN_INFO "%s: Route Removed Sucessfuly: %sn",
- card->devname,in_ntoa(ip_tmp));
- chan->route_flag = NO_ROUTE;
- }
- break;
- } /* Case Statement */
- #else
- /* Dynamic Route adding/removing */
- struct rtentry route;
- int err = 0;
- unsigned long fs = get_fs();
- memset(&route, 0, sizeof(route));
- route.rt_dev = dev->name;
- route.rt_flags = 0;
- ((struct sockaddr_in *) &(route.rt_dst)) ->
- sin_addr.s_addr=dev->pa_dstaddr;
- ((struct sockaddr_in *) &(route.rt_dst)) ->
- sin_family = AF_INET;
- ((struct sockaddr_in *) &(route.rt_genmask)) ->
- sin_addr.s_addr = 0xFFFFFFFF;
- ((struct sockaddr_in *) &(route.rt_genmask)) ->
- sin_family = AF_INET;
- switch(chan->route_flag) {
- case ADD_ROUTE:
- set_fs(get_ds()); /* get user space block */
- err = ip_rt_new(&route);
- set_fs(fs); /* restore old block */
- if (err) {
- printk(KERN_INFO "%s: Adding of route failed. Error: %dn",
- card->devname,err);
- printk(KERN_INFO "%s: Address: %sn",
- chan->name, in_ntoa(dev->pa_dstaddr) );
- }
- else {
- chan->route_flag = ROUTE_ADDED;
- }
- break;
- case REMOVE_ROUTE:
- set_fs(get_ds()); /* get user space block */
- err = ip_rt_kill(&route);
- set_fs(fs); /* restore old block */
- if (err) {
- printk(KERN_INFO "%s: Deleting of route failed. Error: %dn",
- card->devname,err);
- printk(KERN_INFO "%s: Address: %sn",
- dev->name,in_ntoa(dev->pa_dstaddr) );
- } else {
- printk(KERN_INFO "%s: Removed route.n",
- ((fr_channel_t*)dev->priv)->name);
- chan->route_flag = NO_ROUTE;
- }
- break;
- }
- #endif
- }
- /****** Frame Relay Firmware-Specific Functions *****************************/
- /*============================================================================
- * Read firmware code version.
- * o fill string str with firmware version info.
- */
- static int fr_read_version (sdla_t* card, char* str)
- {
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- mbox->cmd.command = FR_READ_CODE_VERSION;
- mbox->cmd.length = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
-
- if (!err && str) {
- int len = mbox->cmd.length;
- memcpy(str, mbox->data, len);
- str[len] = ' ';
- }
- return err;
- }
- /*============================================================================
- * Set global configuration.
- */
- static int fr_configure (sdla_t* card, fr_conf_t *conf)
- {
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int dlci_num = card->u.f.dlci_num;
- int err, i;
- do
- {
- memcpy(mbox->data, conf, sizeof(fr_conf_t));
- if (dlci_num) for (i = 0; i < dlci_num; ++i)
- ((fr_conf_t*)mbox->data)->dlci[i] =
- card->u.f.node_dlci[i];
-
- mbox->cmd.command = FR_SET_CONFIG;
- mbox->cmd.length =
- sizeof(fr_conf_t) + dlci_num * sizeof(short);
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-
- } while (err && retry-- && fr_event(card, err, mbox));
- /*NC Oct 12 2000 */
- if (err != CMD_OK){
- printk(KERN_ERR "%s: Frame Relay Configuration Failed: rc=0x%xn",
- card->devname,err);
- }
-
- return err;
- }
- /*============================================================================
- * Set DLCI configuration.
- */
- static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci)
- {
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- memcpy(mbox->data, conf, sizeof(fr_dlc_conf_t));
- mbox->cmd.dlci = (unsigned short) dlci;
- mbox->cmd.command = FR_SET_CONFIG;
- mbox->cmd.length = sizeof(fr_dlc_conf_t);
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry--);
-
- return err;
- }
- /*============================================================================
- * Set interrupt mode.
- */
- static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu,
- unsigned short timeout)
- {
- fr_mbox_t* mbox = card->mbox;
- fr508_intr_ctl_t* ictl = (void*)mbox->data;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- memset(ictl, 0, sizeof(fr508_intr_ctl_t));
- ictl->mode = mode;
- ictl->tx_len = mtu;
- ictl->irq = card->hw.irq;
- /* indicate timeout on timer */
- if (mode & 0x20) ictl->timeout = timeout;
- mbox->cmd.length = sizeof(fr508_intr_ctl_t);
- mbox->cmd.command = FR_SET_INTR_MODE;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
-
- return err;
- }
- /*============================================================================
- * Enable communications.
- */
- static int fr_comm_enable (sdla_t* card)
- {
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- mbox->cmd.command = FR_COMM_ENABLE;
- mbox->cmd.length = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
-
- return err;
- }
- /*============================================================================
- * fr_comm_disable
- *
- * Warning: This functin is called by the shutdown() procedure. It is void
- * since dev->priv are has already been deallocated and no
- * error checking is possible using fr_event() function.
- */
- static void fr_comm_disable (sdla_t* card)
- {
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do {
- mbox->cmd.command = FR_SET_MODEM_STATUS;
- mbox->cmd.length = 1;
- mbox->data[0] = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry--);
-
- retry = MAX_CMD_RETRY;
-
- do
- {
- mbox->cmd.command = FR_COMM_DISABLE;
- mbox->cmd.length = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry--);
- return;
- }
- /*============================================================================
- * Get communications error statistics.
- */
- static int fr_get_err_stats (sdla_t* card)
- {
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- mbox->cmd.command = FR_READ_ERROR_STATS;
- mbox->cmd.length = 0;
- mbox->cmd.dlci = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
- if (!err) {
- fr_comm_stat_t* stats = (void*)mbox->data;
- card->wandev.stats.rx_over_errors = stats->rx_overruns;
- card->wandev.stats.rx_crc_errors = stats->rx_bad_crc;
- card->wandev.stats.rx_missed_errors = stats->rx_aborts;
- card->wandev.stats.rx_length_errors = stats->rx_too_long;
- card->wandev.stats.tx_aborted_errors = stats->tx_aborts;
-
- }
- return err;
- }
- /*============================================================================
- * Get statistics.
- */
- static int fr_get_stats (sdla_t* card)
- {
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- mbox->cmd.command = FR_READ_STATISTICS;
- mbox->cmd.length = 0;
- mbox->cmd.dlci = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
- if (!err) {
- fr_link_stat_t* stats = (void*)mbox->data;
- card->wandev.stats.rx_frame_errors = stats->rx_bad_format;
- card->wandev.stats.rx_dropped =
- stats->rx_dropped + stats->rx_dropped2;
- }
- return err;
- }
- /*============================================================================
- * Add DLCI(s) (Access Node only!).
- * This routine will perform the ADD_DLCIs command for the specified DLCI.
- */
- static int fr_add_dlci (sdla_t* card, int dlci)
- {
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- unsigned short* dlci_list = (void*)mbox->data;
- mbox->cmd.length = sizeof(short);
- dlci_list[0] = dlci;
- mbox->cmd.command = FR_ADD_DLCI;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
-
- return err;
- }
- /*============================================================================
- * Activate DLCI(s) (Access Node only!).
- * This routine will perform the ACTIVATE_DLCIs command with a DLCI number.
- */
- static int fr_activate_dlci (sdla_t* card, int dlci)
- {
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- unsigned short* dlci_list = (void*)mbox->data;
- mbox->cmd.length = sizeof(short);
- dlci_list[0] = dlci;
- mbox->cmd.command = FR_ACTIVATE_DLCI;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
-
- return err;
- }
- /*============================================================================
- * Delete DLCI(s) (Access Node only!).
- * This routine will perform the DELETE_DLCIs command with a DLCI number.
- */
- static int fr_delete_dlci (sdla_t* card, int dlci)
- {
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- unsigned short* dlci_list = (void*)mbox->data;
- mbox->cmd.length = sizeof(short);
- dlci_list[0] = dlci;
- mbox->cmd.command = FR_DELETE_DLCI;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
-
- return err;
- }
- /*============================================================================
- * Issue in-channel signalling frame.
- */
- static int fr_issue_isf (sdla_t* card, int isf)
- {
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- mbox->data[0] = isf;
- mbox->cmd.length = 1;
- mbox->cmd.command = FR_ISSUE_IS_FRAME;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
-
- return err;
- }
- static unsigned int fr_send_hdr (sdla_t*card, int dlci, unsigned int offset)
- {
- netdevice_t *dev = find_channel(card,dlci);
- fr_channel_t *chan;
- if (!dev || !(chan=dev->priv))
- return offset;
-
- if (chan->fr_header_len){
- sdla_poke(&card->hw, offset, chan->fr_header, chan->fr_header_len);
- }
-
- return offset+chan->fr_header_len;
- }
- /*============================================================================
- * Send a frame on a selected DLCI.
- */
- static int fr_send_data_header (sdla_t* card, int dlci, unsigned char attr, int len,
- void *buf, unsigned char hdr_len)
- {
- fr_mbox_t* mbox = card->mbox + 0x800;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- mbox->cmd.dlci = dlci;
- mbox->cmd.attr = attr;
- mbox->cmd.length = len+hdr_len;
- mbox->cmd.command = FR_WRITE;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
- if (!err) {
- fr_tx_buf_ctl_t* frbuf;
-
- if(card->hw.type == SDLA_S514)
- frbuf = (void*)(*(unsigned long*)mbox->data +
- card->hw.dpmbase);
- else
- frbuf = (void*)(*(unsigned long*)mbox->data -
- FR_MB_VECTOR + card->hw.dpmbase);
- sdla_poke(&card->hw, fr_send_hdr(card,dlci,frbuf->offset), buf, len);
- frbuf->flag = 0x01;
- }
- return err;
- }
- static int fr_send (sdla_t* card, int dlci, unsigned char attr, int len,
- void *buf)
- {
- fr_mbox_t* mbox = card->mbox + 0x800;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- mbox->cmd.dlci = dlci;
- mbox->cmd.attr = attr;
- mbox->cmd.length = len;
- mbox->cmd.command = FR_WRITE;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
- if (!err) {
- fr_tx_buf_ctl_t* frbuf;
-
- if(card->hw.type == SDLA_S514)
- frbuf = (void*)(*(unsigned long*)mbox->data +
- card->hw.dpmbase);
- else
- frbuf = (void*)(*(unsigned long*)mbox->data -
- FR_MB_VECTOR + card->hw.dpmbase);
- sdla_poke(&card->hw, frbuf->offset, buf, len);
- frbuf->flag = 0x01;
- }
- return err;
- }
- /****** Firmware Asynchronous Event Handlers ********************************/
- /*============================================================================
- * Main asyncronous event/error handler.
- * This routine is called whenever firmware command returns non-zero
- * return code.
- *
- * Return zero if previous command has to be cancelled.
- */
- static int fr_event (sdla_t *card, int event, fr_mbox_t* mbox)
- {
- fr508_flags_t* flags = card->flags;
- char *ptr = &flags->iflag;
- int i;
- switch (event) {
- case FRRES_MODEM_FAILURE:
- return fr_modem_failure(card, mbox);
- case FRRES_CHANNEL_DOWN:
- {
- netdevice_t *dev;
- /* Remove all routes from associated DLCI's */
- for (dev = card->wandev.dev; dev; dev = *((netdevice_t **)dev->priv)) {
- fr_channel_t *chan = dev->priv;
- if (chan->route_flag == ROUTE_ADDED) {
- chan->route_flag = REMOVE_ROUTE;
- }
- if (chan->inarp == INARP_CONFIGURED) {
- chan->inarp = INARP_REQUEST;
- }
- /* If the link becomes disconnected then,
- * all channels will be disconnected
- * as well.
- */
- set_chan_state(dev,WAN_DISCONNECTED);
- }
-
- wanpipe_set_state(card, WAN_DISCONNECTED);
- return 1;
- }
- case FRRES_CHANNEL_UP:
- {
- netdevice_t *dev;
- /* FIXME: Only startup devices that are on the list */
-
- for (dev = card->wandev.dev; dev; dev = *((netdevice_t **)dev->priv)) {
-
- set_chan_state(dev,WAN_CONNECTED);
- }
- wanpipe_set_state(card, WAN_CONNECTED);
- return 1;
- }
- case FRRES_DLCI_CHANGE:
- return fr_dlci_change(card, mbox);
- case FRRES_DLCI_MISMATCH:
- printk(KERN_INFO "%s: DLCI list mismatch!n",
- card->devname);
- return 1;
- case CMD_TIMEOUT:
- printk(KERN_ERR "%s: command 0x%02X timed out!n",
- card->devname, mbox->cmd.command);
- printk(KERN_INFO "%s: ID Bytes = ",card->devname);
- for(i = 0; i < 8; i ++)
- printk(KERN_INFO "0x%02X ", *(ptr + 0x18 + i));
- printk(KERN_INFO "n");
-
- break;
- case FRRES_DLCI_INACTIVE:
- break;
-
- case FRRES_CIR_OVERFLOW:
- break;
-
- case FRRES_BUFFER_OVERFLOW:
- break;
-
- default:
- printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!n"
- , card->devname, mbox->cmd.command, event);
- }
- return 0;
- }
- /*============================================================================
- * Handle modem error.
- *
- * Return zero if previous command has to be cancelled.
- */
- static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox)
- {
- printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)n",
- card->devname, mbox->data[0]);
- switch (mbox->cmd.command){
- case FR_WRITE:
-
- case FR_READ:
- return 0;
- }
-
- return 1;
- }
- /*============================================================================
- * Handle DLCI status change.
- *
- * Return zero if previous command has to be cancelled.
- */
- static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox)
- {
- dlci_status_t* status = (void*)mbox->data;
- int cnt = mbox->cmd.length / sizeof(dlci_status_t);
- fr_channel_t *chan;
- netdevice_t* dev2;
-
- for (; cnt; --cnt, ++status) {
- unsigned short dlci= status->dlci;
- netdevice_t* dev = find_channel(card, dlci);
-
- if (dev == NULL){
- printk(KERN_INFO
- "%s: CPE contains unconfigured DLCI= %dn",
- card->devname, dlci);
- printk(KERN_INFO
- "%s: unconfigured DLCI %d reported by networkn"
- , card->devname, dlci);
-
- }else{
- if (status->state == FR_LINK_INOPER) {
- printk(KERN_INFO
- "%s: DLCI %u is inactive!n",
- card->devname, dlci);
- if (dev && is_dev_running(dev))
- set_chan_state(dev, WAN_DISCONNECTED);
- }
-
- if (status->state & FR_DLCI_DELETED) {
- printk(KERN_INFO
- "%s: DLCI %u has been deleted!n",
- card->devname, dlci);
- if (dev && is_dev_running(dev)){
- fr_channel_t *chan = dev->priv;
- if (chan->route_flag == ROUTE_ADDED) {
- chan->route_flag = REMOVE_ROUTE;
- /* The state change will trigger
- * the fr polling routine */
- }
- if (chan->inarp == INARP_CONFIGURED) {
- chan->inarp = INARP_REQUEST;
- }
- set_chan_state(dev, WAN_DISCONNECTED);
- }
- } else if (status->state & FR_DLCI_ACTIVE) {
- chan = dev->priv;
-
- /* This flag is used for configuring specific
- DLCI(s) when they become active.
- */
- chan->dlci_configured = DLCI_CONFIG_PENDING;
-
- set_chan_state(dev, WAN_CONNECTED);
-
- }
- }
- }
-
- for (dev2 =card->wandev.dev; dev2; dev2 = *((netdevice_t **)dev2->priv)){
-
- chan = dev2->priv;
-
- if (chan->dlci_configured == DLCI_CONFIG_PENDING) {
- if (fr_init_dlci(card, chan)){
- return 1;
- }
- }
- }
- return 1;
- }
- static int fr_init_dlci (sdla_t *card, fr_channel_t *chan)
- {
- fr_dlc_conf_t cfg;
-
- memset(&cfg, 0, sizeof(cfg));
- if ( chan->cir_status == CIR_DISABLED) {
- cfg.cir_fwd = cfg.cir_bwd = 16;
- cfg.bc_fwd = cfg.bc_bwd = 16;
- cfg.conf_flags = 0x0001;
- }else if (chan->cir_status == CIR_ENABLED) {
-
- cfg.cir_fwd = cfg.cir_bwd = chan->cir;
- cfg.bc_fwd = cfg.bc_bwd = chan->bc;
- cfg.be_fwd = cfg.be_bwd = chan->be;
- cfg.conf_flags = 0x0000;
- }
-
- if (fr_dlci_configure( card, &cfg , chan->dlci)){
- printk(KERN_INFO
- "%s: DLCI Configure failed for %dn",
- card->devname, chan->dlci);
- return 1;
- }
-
- chan->dlci_configured = DLCI_CONFIGURED;
- /* Read the interface byte mapping into the channel
- * structure.
- */
- read_DLCI_IB_mapping( card, chan );
- return 0;
- }
- /******* Miscellaneous ******************************************************/
- /*============================================================================
- * Update channel state.
- */
- static int update_chan_state (netdevice_t* dev)
- {
- fr_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- int err;
- do
- {
- mbox->cmd.command = FR_LIST_ACTIVE_DLCI;
- mbox->cmd.length = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
- if (!err) {
-
- unsigned short* list = (void*)mbox->data;
- int cnt = mbox->cmd.length / sizeof(short);
-
- err=1;
-
- for (; cnt; --cnt, ++list) {
- if (*list == chan->dlci) {
- set_chan_state(dev, WAN_CONNECTED);
- /* May 23 2000. NC
- * When a dlci is added or restarted,
- * the dlci_int_interface pointer must
- * be reinitialized. */
- if (!chan->dlci_int_interface){
- err=fr_init_dlci (card,chan);
- }
- break;
- }
- }
- }
- return err;
- }
- /*============================================================================
- * Set channel state.
- */
- static void set_chan_state (netdevice_t* dev, int state)
- {
- fr_channel_t* chan = dev->priv;
- sdla_t* card = chan->card;
- if (chan->common.state != state) {
- switch (state) {
- case WAN_CONNECTED:
- printk(KERN_INFO
- "%s: Interface %s: DLCI %d connectedn",
- card->devname, dev->name, chan->dlci);
- /* If the interface was previoulsy down,
- * bring it up, since the channel is active */
- trigger_fr_poll (dev);
- trigger_fr_arp (dev);
- break;
- case WAN_CONNECTING:
- printk(KERN_INFO
- "%s: Interface %s: DLCI %d connectingn",
- card->devname, dev->name, chan->dlci);
- break;
- case WAN_DISCONNECTED:
- printk (KERN_INFO
- "%s: Interface %s: DLCI %d disconnected!n",
- card->devname, dev->name, chan->dlci);
-
- /* If the interface is up, bring it down,
- * since the channel is now disconnected */
- trigger_fr_poll (dev);
- break;
- }
- chan->common.state = state;
- }
- chan->state_tick = jiffies;
- }
- /*============================================================================
- * Find network device by its channel number.
- *
- * We need this critical flag because we change
- * the dlci_to_dev_map outside the interrupt.
- *
- * NOTE: del_if() functions updates this array, it uses
- * the spin locks to avoid corruption.
- */
- static netdevice_t* find_channel (sdla_t* card, unsigned dlci)
- {
- if(dlci > HIGHEST_VALID_DLCI)
- return NULL;
- return(card->u.f.dlci_to_dev_map[dlci]);
- }
- /*============================================================================
- * Check to see if a frame can be sent. If no transmit buffers available,
- * enable transmit interrupts.
- *
- * Return: 1 - Tx buffer(s) available
- * 0 - no buffers available
- */
- static int is_tx_ready (sdla_t* card, fr_channel_t* chan)
- {
- unsigned char sb;
- if(card->hw.type == SDLA_S514)
- return 1;
- sb = inb(card->hw.port);
- if (sb & 0x02)
- return 1;
- return 0;
- }
- /*============================================================================
- * Convert decimal string to unsigned integer.
- * If len != 0 then only 'len' characters of the string are converted.
- */
- static unsigned int dec_to_uint (unsigned char* str, int len)
- {
- unsigned val;
- if (!len)
- len = strlen(str);
- for (val = 0; len && is_digit(*str); ++str, --len)
- val = (val * 10) + (*str - (unsigned)'0');
- return val;
- }
- /*=============================================================================
- * Store a UDP management packet for later processing.
- */
- static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card,
- struct sk_buff *skb, int dlci)
- {
- int udp_pkt_stored = 0;
-
- netdevice_t *dev=find_channel(card,dlci);
- fr_channel_t *chan;
-
- if (!dev || !(chan=dev->priv))
- return 1;
-
- if(!card->u.f.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){
- card->u.f.udp_pkt_lgth = skb->len + chan->fr_header_len;
- card->u.f.udp_type = udp_type;
- card->u.f.udp_pkt_src = udp_pkt_src;
- card->u.f.udp_dlci = dlci;
- memcpy(card->u.f.udp_pkt_data, skb->data, skb->len);
- card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UDP;
- udp_pkt_stored = 1;
- }else{
- printk(KERN_INFO "ERROR: UDP packet not stored for DLCI %dn",
- dlci);
- }
- if(udp_pkt_src == UDP_PKT_FRM_STACK){
- wan_dev_kfree_skb(skb, FREE_WRITE);
- }else{
- wan_dev_kfree_skb(skb, FREE_READ);
- }
-
- return(udp_pkt_stored);
- }
- /*==============================================================================
- * Process UDP call of type FPIPE8ND
- */
- static int process_udp_mgmt_pkt(sdla_t* card)
- {
- int c_retry = MAX_CMD_RETRY;
- unsigned char *buf;
- unsigned char frames;
- unsigned int len;
- unsigned short buffer_length;
- struct sk_buff *new_skb;
- fr_mbox_t* mbox = card->mbox;
- int err;
- struct timeval tv;
- int udp_mgmt_req_valid = 1;
- netdevice_t* dev;
- fr_channel_t* chan;
- fr_udp_pkt_t *fr_udp_pkt;
- unsigned short num_trc_els;
- fr_trc_el_t* ptr_trc_el;
- fr_trc_el_t trc_el;
- fpipemon_trc_t* fpipemon_trc;
- char udp_pkt_src = card->u.f.udp_pkt_src;
- int dlci = card->u.f.udp_dlci;
- /* Find network interface for this packet */
- dev = find_channel(card, dlci);
- if (!dev){
- card->u.f.udp_pkt_lgth = 0;
- return 1;
- }
- if ((chan = dev->priv) == NULL){
- card->u.f.udp_pkt_lgth = 0;
- return 1;
- }
- /* If the UDP packet is from the network, we are going to have to
- transmit a response. Before doing so, we must check to see that
- we are not currently transmitting a frame (in 'if_send()') and
- that we are not already in a 'delayed transmit' state.
- */
- if(udp_pkt_src == UDP_PKT_FRM_NETWORK) {
- if (check_tx_status(card,dev)){
- card->u.f.udp_pkt_lgth = 0;
- return 1;
- }
- }
- fr_udp_pkt = (fr_udp_pkt_t *)card->u.f.udp_pkt_data;
- if(udp_pkt_src == UDP_PKT_FRM_NETWORK) {
-
- switch(fr_udp_pkt->cblock.command) {
- case FR_READ_MODEM_STATUS:
- case FR_READ_STATUS:
- case FPIPE_ROUTER_UP_TIME:
- case FR_READ_ERROR_STATS:
- case FPIPE_DRIVER_STAT_GEN:
- case FR_READ_STATISTICS:
- case FR_READ_ADD_DLC_STATS:
- case FR_READ_CONFIG:
- case FR_READ_CODE_VERSION:
- udp_mgmt_req_valid = 1;
- break;
- default:
- udp_mgmt_req_valid = 0;
- break;
- }
- }
- if(!udp_mgmt_req_valid) {
- /* set length to 0 */
- fr_udp_pkt->cblock.length = 0;
- /* set return code */
- fr_udp_pkt->cblock.result = 0xCD;
-
- chan->drvstats_gen.UDP_PIPE_mgmt_direction_err ++;
- if (net_ratelimit()){
- printk(KERN_INFO
- "%s: Warning, Illegal UDP command attempted from network: %xn",
- card->devname,fr_udp_pkt->cblock.command);
- }
-
- } else {
-
- switch(fr_udp_pkt->cblock.command) {
- case FPIPE_ENABLE_TRACING:
- if(!card->TracingEnabled) {
- do {
- mbox->cmd.command = FR_SET_TRACE_CONFIG;
- mbox->cmd.length = 1;
- mbox->cmd.dlci = 0x00;
- mbox->data[0] = fr_udp_pkt->data[0] |
- RESET_TRC;
- err = sdla_exec(mbox) ?
- mbox->cmd.result : CMD_TIMEOUT;
- } while (err && c_retry-- && fr_event(card, err,
- mbox));
- if(err) {
- card->TracingEnabled = 0;
- /* set the return code */
- fr_udp_pkt->cblock.result =
- mbox->cmd.result;
- mbox->cmd.length = 0;
- break;
- }
- sdla_peek(&card->hw, NO_TRC_ELEMENTS_OFF,
- &num_trc_els, 2);
- sdla_peek(&card->hw, BASE_TRC_ELEMENTS_OFF,
- &card->u.f.trc_el_base, 4);
- card->u.f.curr_trc_el = card->u.f.trc_el_base;
- card->u.f.trc_el_last = card->u.f.curr_trc_el +
- ((num_trc_els - 1) *
- sizeof(fr_trc_el_t));
-
- /* Calculate the maximum trace data area in */
- /* the UDP packet */
- card->u.f.trc_bfr_space=(MAX_LGTH_UDP_MGNT_PKT -
- //sizeof(fr_encap_hdr_t) -
- sizeof(ip_pkt_t) -
- sizeof(udp_pkt_t) -
- sizeof(wp_mgmt_t) -
- sizeof(cblock_t));
- /* set return code */
- fr_udp_pkt->cblock.result = 0;
-
- } else {
- /* set return code to line trace already
- enabled */
- fr_udp_pkt->cblock.result = 1;
- }
- mbox->cmd.length = 0;
- card->TracingEnabled = 1;
- break;
- case FPIPE_DISABLE_TRACING:
- if(card->TracingEnabled) {
-
- do {
- mbox->cmd.command = FR_SET_TRACE_CONFIG;
- mbox->cmd.length = 1;
- mbox->cmd.dlci = 0x00;
- mbox->data[0] = ~ACTIVATE_TRC;
- err = sdla_exec(mbox) ?
- mbox->cmd.result : CMD_TIMEOUT;
- } while (err && c_retry-- && fr_event(card, err, mbox));
- }
- /* set return code */
- fr_udp_pkt->cblock.result = 0;
- mbox->cmd.length = 0;
- card->TracingEnabled = 0;
- break;
- case FPIPE_GET_TRACE_INFO:
- /* Line trace cannot be performed on the 502 */
- if(!card->TracingEnabled) {
- /* set return code */
- fr_udp_pkt->cblock.result = 1;
- mbox->cmd.length = 0;
- break;
- }
- (void *)ptr_trc_el = card->u.f.curr_trc_el;
- buffer_length = 0;
- fr_udp_pkt->data[0x00] = 0x00;
- for(frames = 0; frames < MAX_FRMS_TRACED; frames ++) {
- sdla_peek(&card->hw, (unsigned long)ptr_trc_el,
- (void *)&trc_el.flag,
- sizeof(fr_trc_el_t));
- if(trc_el.flag == 0x00) {
- break;
- }
- if((card->u.f.trc_bfr_space - buffer_length)
- < sizeof(fpipemon_trc_hdr_t)) {
- fr_udp_pkt->data[0x00] |= MORE_TRC_DATA;
- break;
- }
- fpipemon_trc =
- (fpipemon_trc_t *)&fr_udp_pkt->data[buffer_length];
- fpipemon_trc->fpipemon_trc_hdr.status =
- trc_el.attr;
- fpipemon_trc->fpipemon_trc_hdr.tmstamp =
- trc_el.tmstamp;
- fpipemon_trc->fpipemon_trc_hdr.length =
- trc_el.length;
- if(!trc_el.offset || !trc_el.length) {
- fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00;
- }else if((trc_el.length + sizeof(fpipemon_trc_hdr_t) + 1) >
- (card->u.f.trc_bfr_space - buffer_length)){
- fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00;
- fr_udp_pkt->data[0x00] |= MORE_TRC_DATA;
-
- }else {
- fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x01;
- sdla_peek(&card->hw, trc_el.offset,
- fpipemon_trc->data,
- trc_el.length);
- }
- trc_el.flag = 0x00;
- sdla_poke(&card->hw, (unsigned long)ptr_trc_el,
- &trc_el.flag, 1);
-
- ptr_trc_el ++;
- if((void *)ptr_trc_el > card->u.f.trc_el_last)
- (void*)ptr_trc_el = card->u.f.trc_el_base;
- buffer_length += sizeof(fpipemon_trc_hdr_t);
- if(fpipemon_trc->fpipemon_trc_hdr.data_passed) {
- buffer_length += trc_el.length;
- }
- if(fr_udp_pkt->data[0x00] & MORE_TRC_DATA) {
- break;
- }
- }
-
- if(frames == MAX_FRMS_TRACED) {
- fr_udp_pkt->data[0x00] |= MORE_TRC_DATA;
- }
-
- card->u.f.curr_trc_el = (void *)ptr_trc_el;
- /* set the total number of frames passed */
- fr_udp_pkt->data[0x00] |=
- ((frames << 1) & (MAX_FRMS_TRACED << 1));
- /* set the data length and return code */
- fr_udp_pkt->cblock.length = mbox->cmd.length = buffer_length;
- fr_udp_pkt->cblock.result = 0;
- break;
- case FPIPE_FT1_READ_STATUS:
- sdla_peek(&card->hw, 0xF020,
- &fr_udp_pkt->data[0x00] , 2);
- fr_udp_pkt->cblock.length = mbox->cmd.length = 2;
- fr_udp_pkt->cblock.result = 0;
- break;
- case FPIPE_FLUSH_DRIVER_STATS:
- init_chan_statistics(chan);
- init_global_statistics(card);
- mbox->cmd.length = 0;
- break;
-
- case FPIPE_ROUTER_UP_TIME:
- do_gettimeofday(&tv);
- chan->router_up_time = tv.tv_sec -
- chan->router_start_time;
- *(unsigned long *)&fr_udp_pkt->data =
- chan->router_up_time;
- mbox->cmd.length = fr_udp_pkt->cblock.length = 4;
- fr_udp_pkt->cblock.result = 0;
- break;
- case FPIPE_DRIVER_STAT_IFSEND:
- memcpy(fr_udp_pkt->data,
- &chan->drvstats_if_send.if_send_entry,
- sizeof(if_send_stat_t));
- mbox->cmd.length = fr_udp_pkt->cblock.length =sizeof(if_send_stat_t);
- fr_udp_pkt->cblock.result = 0;
- break;
-
- case FPIPE_DRIVER_STAT_INTR:
- memcpy(fr_udp_pkt->data,
- &card->statistics.isr_entry,
- sizeof(global_stats_t));
- memcpy(&fr_udp_pkt->data[sizeof(global_stats_t)],
- &chan->drvstats_rx_intr.rx_intr_no_socket,
- sizeof(rx_intr_stat_t));
- mbox->cmd.length = fr_udp_pkt->cblock.length =
- sizeof(global_stats_t) +
- sizeof(rx_intr_stat_t);
- fr_udp_pkt->cblock.result = 0;
- break;
- case FPIPE_DRIVER_STAT_GEN:
- memcpy(fr_udp_pkt->data,
- &chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err,
- sizeof(pipe_mgmt_stat_t));
- memcpy(&fr_udp_pkt->data[sizeof(pipe_mgmt_stat_t)],
- &card->statistics, sizeof(global_stats_t));
- mbox->cmd.length = fr_udp_pkt->cblock.length = sizeof(global_stats_t)+
- sizeof(rx_intr_stat_t);
- fr_udp_pkt->cblock.result = 0;
- break;
- case FR_FT1_STATUS_CTRL:
- if(fr_udp_pkt->data[0] == 1) {
- if(rCount++ != 0 ){
- fr_udp_pkt->cblock.result = 0;
- mbox->cmd.length = 1;
- break;
- }
- }
-
- /* Disable FT1 MONITOR STATUS */
- if(fr_udp_pkt->data[0] == 0) {
- if( --rCount != 0) {
- fr_udp_pkt->cblock.result = 0;
- mbox->cmd.length = 1;
- break;
- }
- }
- goto udp_mgmt_dflt;
-
- default:
- udp_mgmt_dflt:
- do {
- memcpy(&mbox->cmd,
- &fr_udp_pkt->cblock.command,
- sizeof(fr_cmd_t));
- if(mbox->cmd.length) {
- memcpy(&mbox->data,
- (char *)fr_udp_pkt->data,
- mbox->cmd.length);
- }
-
- err = sdla_exec(mbox) ? mbox->cmd.result :
- CMD_TIMEOUT;
- } while (err && c_retry-- && fr_event(card, err, mbox));
- if(!err)
- chan->drvstats_gen.
- UDP_PIPE_mgmt_adptr_cmnd_OK ++;
- else
- chan->drvstats_gen.
- UDP_PIPE_mgmt_adptr_cmnd_timeout ++;
- /* copy the result back to our buffer */
- memcpy(&fr_udp_pkt->cblock.command,
- &mbox->cmd, sizeof(fr_cmd_t));
- if(mbox->cmd.length) {
- memcpy(&fr_udp_pkt->data,
- &mbox->data, mbox->cmd.length);
- }
- }
- }
-
- /* Fill UDP TTL */
- fr_udp_pkt->ip_pkt.ttl = card->wandev.ttl;
- len = reply_udp(card->u.f.udp_pkt_data, mbox->cmd.length);
- if(udp_pkt_src == UDP_PKT_FRM_NETWORK) {
- chan->fr_header_len=2;
- chan->fr_header[0]=Q922_UI;
- chan->fr_header[1]=NLPID_IP;
-
- err = fr_send_data_header(card, dlci, 0, len,
- card->u.f.udp_pkt_data,chan->fr_header_len);
- if (err){
- chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_passed ++;
- }else{
- chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_failed ++;
- }
-
- } else {
- /* Allocate socket buffer */
- if((new_skb = dev_alloc_skb(len)) != NULL) {
- /* copy data into new_skb */
- buf = skb_put(new_skb, len);
- memcpy(buf, card->u.f.udp_pkt_data, len);
-
- chan->drvstats_gen.
- UDP_PIPE_mgmt_passed_to_stack ++;
- new_skb->dev = dev;
- new_skb->protocol = htons(ETH_P_IP);
- new_skb->mac.raw = new_skb->data;
- netif_rx(new_skb);
-
- } else {
- chan->drvstats_gen.UDP_PIPE_mgmt_no_socket ++;
- printk(KERN_INFO
- "%s: UDP mgmt cmnd, no socket buffers available!n",
- card->devname);
- }
- }
- card->u.f.udp_pkt_lgth = 0;
- return 1;
- }
- /*==============================================================================
- * Send Inverse ARP Request
- */
- int send_inarp_request(sdla_t *card, netdevice_t *dev)
- {
- int err=0;
- #if defined(LINUX_2_1) || defined(LINUX_2_4)
- arphdr_1490_t *ArpPacket;
- arphdr_fr_t *arphdr;
- fr_channel_t *chan = dev->priv;
- struct in_device *in_dev;
- in_dev = dev->ip_ptr;
- if(in_dev != NULL ) {
- ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC);
- /* SNAP Header indicating ARP */
- ArpPacket->control = 0x03;
- ArpPacket->pad = 0x00;
- ArpPacket->NLPID = 0x80;
- ArpPacket->OUI[0] = 0;
- ArpPacket->OUI[1] = 0;
- ArpPacket->OUI[2] = 0;
- ArpPacket->PID = 0x0608;
- arphdr = (arphdr_fr_t *)(ArpPacket + 1); // Go to ARP Packet
- /* InARP request */
- arphdr->ar_hrd = 0x0F00; /* Frame Relay HW type */
- arphdr->ar_pro = 0x0008; /* IP Protocol */
- arphdr->ar_hln = 2; /* HW addr length */
- arphdr->ar_pln = 4; /* IP addr length */
- arphdr->ar_op = htons(0x08); /* InARP Request */
- arphdr->ar_sha = 0; /* src HW DLCI - Doesn't matter */
- if(in_dev->ifa_list != NULL)
- arphdr->ar_sip = in_dev->ifa_list->ifa_local; /* Local Address */else
- arphdr->ar_sip = 0;
- arphdr->ar_tha = 0; /* dst HW DLCI - Doesn't matter */
- arphdr->ar_tip = 0; /* Remote Address -- what we want */
- err = fr_send(card, chan->dlci, 0, sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t),
- (void *)ArpPacket);
- if (!err){
- printk(KERN_INFO "n%s: Sending InARP request on DLCI %d.n",
- card->devname, chan->dlci);
- clear_bit(ARP_CRIT,&card->wandev.critical);
- }
- kfree(ArpPacket);
- }else{
- printk(KERN_INFO "%s: INARP ERROR: %s doesn't have a local IP address!n",
- card->devname,dev->name);
- return 1;
- }
- #else
- arphdr_1490_t *ArpPacket;
- arphdr_fr_t *arphdr;
- fr_channel_t *chan = dev->priv;
- ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC);
- /* SNAP Header indicating ARP */
- ArpPacket->control = 0x03;
- ArpPacket->pad = 0x00;
- ArpPacket->NLPID = 0x80;
- ArpPacket->OUI[0] = 0;
- ArpPacket->OUI[1] = 0;
- ArpPacket->OUI[2] = 0;
- ArpPacket->PID = 0x0608;
- arphdr = (arphdr_fr_t *)(ArpPacket + 1); // Go to ARP Packet
- /* InARP request */
- arphdr->ar_hrd = 0x0F00; /* Frame Relay HW type */
- arphdr->ar_pro = 0x0008; /* IP Protocol */
- arphdr->ar_hln = 2; /* HW addr length */
- arphdr->ar_pln = 4; /* IP addr length */
- arphdr->ar_op = htons(0x08); /* InARP Request */
- arphdr->ar_sha = 0; /* src HW DLCI - Doesn't matter */
- arphdr->ar_sip = dev->pa_addr; /* Local Address */
- arphdr->ar_tha = 0; /* dst HW DLCI - Doesn't matter */
- arphdr->ar_tip = 0; /* Remote Address -- what we want */
- printk(KERN_INFO "%s: Sending InARP request on DLCI %d.n", card->devname, chan->dlci);
- err = fr_send(card, chan->dlci, 0,
- sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t),
- (void *)ArpPacket);
-
- if (!err){
- printk(KERN_INFO "n%s: Sending InARP request on DLCI %d.n",
- card->devname, chan->dlci);
- clear_bit(ARP_CRIT,&card->wandev.critical);
- }
- kfree(ArpPacket);
- #endif
- return 0;
- }
-
- /*==============================================================================
- * Check packet for ARP Type
- */
- int is_arp(void *buf)
- {
- arphdr_1490_t *arphdr = (arphdr_1490_t *)buf;
-
- if (arphdr->pad == 0x00 &&
- arphdr->NLPID == 0x80 &&
- arphdr->PID == 0x0608)
- return 1;
- else return 0;
- }
- /*==============================================================================
- * Process ARP Packet Type
- */
- int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, netdevice_t* dev)
- {
- #if defined(LINUX_2_1) || defined(LINUX_2_4)
- arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */
- fr_rx_buf_ctl_t* frbuf = card->rxmb;
- struct in_device *in_dev;
- fr_channel_t *chan = dev->priv;
- #else
- arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */
- fr_rx_buf_ctl_t* frbuf = card->rxmb;
- #endif
-
- /* Before we transmit ARP packet, we must check
- * to see that we are not currently transmitting a
- * frame (in 'if_send()') and that we are not
- * already in a 'delayed transmit' state. */
- if (check_tx_status(card,dev)){
- if (net_ratelimit()){
- printk(KERN_INFO "%s: Disabling comminication to process ARPn",
- card->devname);
- }
- set_bit(ARP_CRIT,&card->wandev.critical);
- return 0;
- }
- #if defined(LINUX_2_1) || defined(LINUX_2_4)
- in_dev = dev->ip_ptr;
- /* Check that IP addresses exist for our network address */
- if (in_dev == NULL || in_dev->ifa_list == NULL)
- return -1;
- switch (ntohs(arphdr->ar_op)) {
- case 0x08: // Inverse ARP request -- Send Reply, add route.
-
- /* Check for valid Address */
- printk(KERN_INFO "%s: Recvd PtP addr -InArp Req: %sn",
- card->devname, in_ntoa(arphdr->ar_sip));
- /* Check that the network address is the same as ours, only
- * if the netowrk mask is not 255.255.255.255. Otherwise
- * this check would not make sense */
- if (in_dev->ifa_list->ifa_mask != 0xFFFFFFFF &&
- (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) !=
- (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)){
- printk(KERN_INFO
- "%s: Invalid PtP address. %s InARP ignored.n",
- card->devname,in_ntoa(arphdr->ar_sip));
- printk(KERN_INFO "%s: mask %sn",
- card->devname, in_ntoa(in_dev->ifa_list->ifa_mask));
- printk(KERN_INFO "%s: local %sn",
- card->devname,in_ntoa(in_dev->ifa_list->ifa_local));
- return -1;
- }
- if (in_dev->ifa_list->ifa_local == arphdr->ar_sip){
- printk(KERN_INFO
- "%s: Local addr = PtP addr. InARP ignored.n",
- card->devname);
- return -1;
- }
-
- arphdr->ar_op = htons(0x09); /* InARP Reply */
- /* Set addresses */
- arphdr->ar_tip = arphdr->ar_sip;
- arphdr->ar_sip = in_dev->ifa_list->ifa_local;
- chan->ip_local = in_dev->ifa_list->ifa_local;
- chan->ip_remote = arphdr->ar_sip;
- fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket);
- if (test_bit(ARP_CRIT,&card->wandev.critical)){
- if (net_ratelimit()){
- printk(KERN_INFO "%s: ARP Processed Enabling Communication!n",
- card->devname);
- }
- }
- clear_bit(ARP_CRIT,&card->wandev.critical);
-
- chan->ip_local = in_dev->ifa_list->ifa_local;
- chan->ip_remote = arphdr->ar_sip;
- /* Add Route Flag */
- /* The route will be added in the polling routine so
- that it is not interrupt context. */
- chan->route_flag = ADD_ROUTE;
- trigger_fr_poll (dev);
- break;
- case 0x09: // Inverse ARP reply
- /* Check for valid Address */
- printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Replyn",
- card->devname, in_ntoa(arphdr->ar_sip));
- /* Compare network addresses, only if network mask
- * is not 255.255.255.255 It would not make sense
- * to perform this test if the mask was all 1's */
- if (in_dev->ifa_list->ifa_mask != 0xffffffff &&
- (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) !=
- (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) {
- printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.n",
- card->devname);
- return -1;
- }
- /* Make sure that the received IP address is not
- * the same as our own local address */
- if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) {
- printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.n",
- card->devname);
- return -1;
- }
- chan->ip_local = in_dev->ifa_list->ifa_local;
- chan->ip_remote = arphdr->ar_sip;
- /* Add Route Flag */
- /* The route will be added in the polling routine so
- that it is not interrupt context. */
- chan->route_flag = ADD_ROUTE;
- chan->inarp = INARP_CONFIGURED;
- trigger_fr_poll(dev);
-
- break;
- default:
- break; // ARP's and RARP's -- Shouldn't happen.
- }
- return 0;
- #else
- switch (ntohs(arphdr->ar_op)) {
- case 0x08: // Inverse ARP request -- Send Reply, add route.
- /* Check for valid Address */
- printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Reqn",
- ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip));
- if (dev->pa_mask != 0xFFFFFFFF){
- if ((dev->pa_mask & arphdr->ar_sip) != (dev->pa_mask & dev->pa_addr)) {
- printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.n",
- card->devname);
- return -1;
- }
- }
- if (dev->pa_addr == arphdr->ar_sip) {
- printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.n",
- card->devname);
- return -1;
- }
- arphdr->ar_op = htons(0x09); /* InARP Reply */
- /* Set addresses */
- arphdr->ar_tip = arphdr->ar_sip;
- arphdr->ar_sip = dev->pa_addr;
- fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket);
- clear_bit(ARP_CRIT,&card->wandev.critical);
- /* Modify Point-to-Point Address */
- dev->pa_dstaddr = arphdr->ar_tip;
- /* Add Route Flag */
- /* The route will be added in the polling routine so
- that it is not interrupt context. */
- ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE;
- trigger_fr_poll(dev);
- break;
- case 0x09: // Inverse ARP reply
- /* Check for valid Address */
- printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Replyn",
- ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip));
- if ((dev->pa_mask & arphdr->ar_sip) != (dev->pa_mask & dev->pa_addr)) {
- printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.n",
- card->devname);
- return -1;
- }
- if (dev->pa_addr == arphdr->ar_sip) {
- printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.n",
- card->devname);
- return -1;
- }
- /* Modify Point-to-Point Address */
- dev->pa_dstaddr = arphdr->ar_sip;
- /* Add Route Flag */
- /* The route will be added in the polling routine so
- that it is not interrupt context. */
- ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE;
- ((fr_channel_t *) dev->priv)->inarp = INARP_CONFIGURED;
- trigger_fr_poll(dev);
- break;
- default: // ARP's and RARP's -- Shouldn't happen.
- }
- return 0;
- #endif
- }
- /*============================================================
- * trigger_fr_arp
- *
- * Description:
- * Add an fr_arp() task into a arp
- * timer handler for a specific dlci/interface.
- * This will kick the fr_arp() routine
- * within the specified time interval.
- *
- * Usage:
- * This timer is used to send ARP requests at
- * certain time intervals.
- * Called by an interrupt to request an action
- * at a later date.
- */
- static void trigger_fr_arp (netdevice_t *dev)
- {
- fr_channel_t* chan = dev->priv;
- del_timer(&chan->fr_arp_timer);
- chan->fr_arp_timer.expires = jiffies + (chan->inarp_interval * HZ);
- add_timer(&chan->fr_arp_timer);
- return;
- }
- /*==============================================================================
- * ARP Request Action
- *
- * This funciton is called by timer interrupt to send an arp request
- * to the remote end.
- */
- static void fr_arp (unsigned long data)
- {
- netdevice_t *dev = (netdevice_t *)data;
- fr_channel_t *chan = dev->priv;
- volatile sdla_t *card = chan->card;
- fr508_flags_t* flags = card->flags;
- /* Send ARP packets for all devs' until
- * ARP state changes to CONFIGURED */
- if (chan->inarp == INARP_REQUEST &&
- chan->common.state == WAN_CONNECTED &&
- card->wandev.state == WAN_CONNECTED){
- set_bit(0,&chan->inarp_ready);
- card->u.f.timer_int_enabled |= TMR_INT_ENABLED_ARP;
- flags->imask |= FR_INTR_TIMER;
- }
-
- return;
- }
-
- /*==============================================================================
- * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_
- * TEST_COUNTER times.
- */
- static int intr_test( sdla_t* card )
- {
- fr_mbox_t* mb = card->mbox;
- int err,i;
- err = fr_set_intr_mode(card, FR_INTR_READY, card->wandev.mtu, 0 );
-
- if (err == CMD_OK) {
- for ( i = 0; i < MAX_INTR_TEST_COUNTER; i++ ) {
- /* Run command READ_CODE_VERSION */
- mb->cmd.length = 0;
- mb->cmd.command = FR_READ_CODE_VERSION;
- err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT;
- if (err != CMD_OK)
- fr_event(card, err, mb);
- }
-
- } else {
- return err;
- }
- err = fr_set_intr_mode( card, 0, card->wandev.mtu, 0 );
- if( err != CMD_OK )
- return err;
- return 0;
- }
- /*==============================================================================
- * Determine what type of UDP call it is. FPIPE8ND ?
- */
- static int udp_pkt_type( struct sk_buff *skb, sdla_t* card )
- {
- fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)skb->data;
- /* Quick HACK */
-
-
- if((fr_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) &&
- (fr_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) &&
- (fr_udp_pkt->udp_pkt.udp_dst_port ==
- ntohs(card->wandev.udp_port)) &&
- (fr_udp_pkt->wp_mgmt.request_reply ==
- UDPMGMT_REQUEST)) {
- if(!strncmp(fr_udp_pkt->wp_mgmt.signature,
- UDPMGMT_FPIPE_SIGNATURE, 8)){
- return UDP_FPIPE_TYPE;
- }
- }
- return UDP_INVALID_TYPE;
- }
- /*==============================================================================
- * Initializes the Statistics values in the fr_channel structure.
- */
- void init_chan_statistics( fr_channel_t* chan)
- {
- memset(&chan->drvstats_if_send.if_send_entry, 0,
- sizeof(if_send_stat_t));
- memset(&chan->drvstats_rx_intr.rx_intr_no_socket, 0,
- sizeof(rx_intr_stat_t));
- memset(&chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, 0,
- sizeof(pipe_mgmt_stat_t));
- }
-
- /*==============================================================================
- * Initializes the Statistics values in the Sdla_t structure.
- */
- void init_global_statistics( sdla_t* card )
- {
- /* Intialize global statistics for a card */
- memset(&card->statistics.isr_entry, 0, sizeof(global_stats_t));
- }
- static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan )
- {
- fr_mbox_t* mbox = card->mbox;
- int retry = MAX_CMD_RETRY;
- dlci_IB_mapping_t* result;
- int err, counter, found;
- do {
- mbox->cmd.command = FR_READ_DLCI_IB_MAPPING;
- mbox->cmd.length = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- } while (err && retry-- && fr_event(card, err, mbox));
- if( mbox->cmd.result != 0){
- printk(KERN_INFO "%s: Read DLCI IB Mapping failedn",
- chan->name);
- }
- counter = mbox->cmd.length / sizeof(dlci_IB_mapping_t);
- result = (void *)mbox->data;
-
- found = 0;
- for (; counter; --counter, ++result) {
- if ( result->dlci == chan->dlci ) {
- chan->IB_addr = result->addr_value;
- if(card->hw.type == SDLA_S514){
- chan->dlci_int_interface =
- (void*)(card->hw.dpmbase +
- chan->IB_addr);
- }else{
- chan->dlci_int_interface =
- (void*)(card->hw.dpmbase +
- (chan->IB_addr & 0x00001FFF));
- }
- found = 1;
- break;
- }
- }
- if (!found)
- printk( KERN_INFO "%s: DLCI %d not found by IB MAPPING cmdn",
- card->devname, chan->dlci);
- }
- void s508_s514_lock(sdla_t *card, unsigned long *smp_flags)
- {
- if (card->hw.type != SDLA_S514){
- #if defined(__SMP__) || defined(LINUX_2_4)
- spin_lock_irqsave(&card->wandev.lock, *smp_flags);
- #else
- disable_irq(card->hw.irq);
- #endif
- }else{
- #if defined(__SMP__) || defined(LINUX_2_4)
- spin_lock(&card->u.f.if_send_lock);
- #endif
- }
- return;
- }
- void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags)
- {
- if (card->hw.type != SDLA_S514){
- #if defined(__SMP__) || defined(LINUX_2_4)
- spin_unlock_irqrestore (&card->wandev.lock, *smp_flags);
- #else
- enable_irq(card->hw.irq);
- #endif
- }else{
- #if defined(__SMP__) || defined(LINUX_2_4)
- spin_unlock(&card->u.f.if_send_lock);
- #endif
- }
- return;
- }
- #if defined(LINUX_2_1) || defined(LINUX_2_4)
- /*----------------------------------------------------------------------
- RECEIVE INTERRUPT: BOTTOM HALF HANDLERS
- ----------------------------------------------------------------------*/
- /*========================================================
- * bh_enqueue
- *
- * Description:
- * Insert a received packed into a circular
- * rx queue. This packed will be picked up
- * by fr_bh() and sent up the stack to the
- * user.
- *
- * Usage:
- * This function is called by rx interrupt,
- * in API mode.
- *
- */
- static int bh_enqueue (netdevice_t *dev, struct sk_buff *skb)
- {
- /* Check for full */
- fr_channel_t* chan = dev->priv;
- sdla_t *card = chan->card;
- if (atomic_read(&chan->bh_buff_used) == MAX_BH_BUFF){
- ++card->wandev.stats.rx_dropped;
- wan_dev_kfree_skb(skb, FREE_READ);
- return 1;
- }
- ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb;
- if (chan->bh_write == (MAX_BH_BUFF-1)){
- chan->bh_write=0;
- }else{
- ++chan->bh_write;
- }
- atomic_inc(&chan->bh_buff_used);
- return 0;
- }
- /*========================================================
- * trigger_fr_bh
- *
- * Description:
- * Kick the fr_bh() handler
- *
- * Usage:
- * rx interrupt calls this function during
- * the API mode.
- */
- static void trigger_fr_bh (fr_channel_t *chan)
- {
- if (!test_and_set_bit(0,&chan->tq_working)){
- wanpipe_queue_tq(&chan->common.wanpipe_task);
- wanpipe_mark_bh();
- }
- }
- /*========================================================
- * fr_bh
- *
- * Description:
- * Frame relay receive BH handler.
- * Dequeue data from the BH circular
- * buffer and pass it up the API sock.
- *
- * Rationale:
- * This fuction is used to offload the
- * rx_interrupt during API operation mode.
- * The fr_bh() function executes for each
- * dlci/interface.
- *
- * Once receive interrupt copies data from the
- * card into an skb buffer, the skb buffer
- * is appended to a circular BH buffer.
- * Then the interrupt kicks fr_bh() to finish the
- * job at a later time (no within the interrupt).
- *
- * Usage:
- * Interrupts use this to defer a taks to
- * a polling routine.
- *
- */
- static void fr_bh (netdevice_t * dev)
- {
- fr_channel_t* chan = dev->priv;
- sdla_t *card = chan->card;
- struct sk_buff *skb;
- if (atomic_read(&chan->bh_buff_used) == 0){
- clear_bit(0, &chan->tq_working);
- return;
- }
- while (atomic_read(&chan->bh_buff_used)){
- if (chan->common.sk == NULL || chan->common.func == NULL){
- clear_bit(0, &chan->tq_working);
- return;
- }
- skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb;
- if (skb != NULL){
- if (chan->common.sk == NULL || chan->common.func == NULL){
- ++card->wandev.stats.rx_dropped;
- ++chan->ifstats.rx_dropped;
- wan_dev_kfree_skb(skb, FREE_READ);
- fr_bh_cleanup(dev);
- continue;
- }
- if (chan->common.func(skb,dev,chan->common.sk) != 0){
- /* Sock full cannot send, queue us for
- * another try */
- atomic_set(&chan->common.receive_block,1);
- return;
- }else{
- fr_bh_cleanup(dev);
- }
- }else{
- fr_bh_cleanup(dev);
- }
- }
- clear_bit(0, &chan->tq_working);
- return;
- }
- static int fr_bh_cleanup (netdevice_t *dev)
- {
- fr_channel_t* chan = dev->priv;
- ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL;
- if (chan->bh_read == (MAX_BH_BUFF-1)){
- chan->bh_read=0;
- }else{
- ++chan->bh_read;
- }
- atomic_dec(&chan->bh_buff_used);
- return 0;
- }
- #endif
- /*----------------------------------------------------------------------
- POLL BH HANDLERS AND KICK ROUTINES
- ----------------------------------------------------------------------*/
- /*============================================================
- * trigger_fr_poll
- *
- * Description:
- * Add a fr_poll() task into a tq_scheduler bh handler
- * for a specific dlci/interface. This will kick
- * the fr_poll() routine at a later time.
- *
- * Usage:
- * Interrupts use this to defer a taks to
- * a polling routine.
- *
- */
- static void trigger_fr_poll (netdevice_t *dev)
- {
- fr_channel_t* chan = dev->priv;
- #ifdef LINUX_2_4
- schedule_task(&chan->fr_poll_task);
- #else
- queue_task(&chan->fr_poll_task, &tq_scheduler);
- #endif
- return;
- }
- /*============================================================
- * fr_poll
- *
- * Rationale:
- * We cannot manipulate the routing tables, or
- * ip addresses withing the interrupt. Therefore
- * we must perform such actons outside an interrupt
- * at a later time.
- *
- * Description:
- * Frame relay polling routine, responsible for
- * shutting down interfaces upon disconnect
- * and adding/removing routes.
- *
- * Usage:
- * This function is executed for each frame relay
- * dlci/interface through a tq_schedule bottom half.
- *
- * trigger_fr_poll() function is used to kick
- * the fr_poll routine.
- */
- static void fr_poll (netdevice_t *dev)
- {
- fr_channel_t* chan;
- sdla_t *card;
- u8 check_gateway=0;
- if (!dev || (chan = dev->priv) == NULL)
- return;
- card = chan->card;
-
- /* (Re)Configuraiton is in progress, stop what you are
- * doing and get out */
- if (test_bit(PERI_CRIT,&card->wandev.critical)){
- return;
- }
- switch (chan->common.state){
- case WAN_DISCONNECTED:
- if (test_bit(DYN_OPT_ON,&chan->interface_down) &&
- !test_bit(DEV_DOWN, &chan->interface_down) &&
- dev->flags&IFF_UP){
- printk(KERN_INFO "%s: Interface %s is Down.n",
- card->devname,dev->name);
- change_dev_flags(dev,dev->flags&~IFF_UP);
- set_bit(DEV_DOWN, &chan->interface_down);
- chan->route_flag = NO_ROUTE;
-
- }else{
- if (chan->inarp != INARP_NONE)
- process_route(dev);
- }
- break;
- case WAN_CONNECTED:
- if (test_bit(DYN_OPT_ON,&chan->interface_down) &&
- test_bit(DEV_DOWN, &chan->interface_down) &&
- !(dev->flags&IFF_UP)){
- printk(KERN_INFO "%s: Interface %s is Up.n",
- card->devname,dev->name);
- change_dev_flags(dev,dev->flags|IFF_UP);
- clear_bit(DEV_DOWN, &chan->interface_down);
- check_gateway=1;
- }
- if (chan->inarp != INARP_NONE){
- process_route(dev);
- check_gateway=1;
- }
- if (chan->gateway && check_gateway)
- add_gateway(card,dev);
- break;
- }
- return;
- }
- /*==============================================================
- * check_tx_status
- *
- * Rationale:
- * We cannot transmit from an interrupt while
- * the if_send is transmitting data. Therefore,
- * we must check whether the tx buffers are
- * begin used, before we transmit from an
- * interrupt.
- *
- * Description:
- * Checks whether it's safe to use the transmit
- * buffers.
- *
- * Usage:
- * ARP and UDP handling routines use this function
- * because, they need to transmit data during
- * an interrupt.
- */
- static int check_tx_status(sdla_t *card, netdevice_t *dev)
- {
- if (card->hw.type == SDLA_S514){
- if (test_bit(SEND_CRIT, (void*)&card->wandev.critical) ||
- test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) {
- return 1;
- }
- }
- if (is_queue_stopped(dev) || (card->u.f.tx_interrupts_pending))
- return 1;
- return 0;
- }
- /*===============================================================
- * move_dev_to_next
- *
- * Description:
- * Move the dev pointer to the next location in the
- * link list. Check if we are at the end of the
- * list, if so start from the begining.
- *
- * Usage:
- * Timer interrupt uses this function to efficiently
- * step through the devices that need to send ARP data.
- *
- */
- netdevice_t * move_dev_to_next (sdla_t *card, netdevice_t *dev)
- {
- if (card->wandev.new_if_cnt != 1){
- if (*((netdevice_t **)dev->priv) == NULL){
- return card->wandev.dev;
- }else{
- return *((netdevice_t **)dev->priv);
- }
- }
- return dev;
- }
- /*==============================================================
- * trigger_config_fr
- *
- * Rationale:
- * All commands must be performed inside of a
- * interrupt.
- *
- * Description:
- * Kick the config_fr() routine throught the
- * timer interrupt.
- */
- static void trigger_config_fr (sdla_t *card)
- {
- fr508_flags_t* flags = card->flags;
- card->u.f.timer_int_enabled |= TMR_INT_ENABLED_CONFIG;
- flags->imask |= FR_INTR_TIMER;
- }
- /*==============================================================
- * config_fr
- *
- * Rationale:
- * All commands must be performed inside of a
- * interrupt.
- &
- * Description:
- * Configure a DLCI. This function is executed
- * by a timer_interrupt. The if_open() function
- * triggers it.
- *
- * Usage:
- * new_if() collects all data necessary to
- * configure the DLCI. It sets the chan->dlci_ready
- * bit. When the if_open() function is executed
- * it checks this bit, and if its set it triggers
- * the timer interrupt to execute the config_fr()
- * function.
- */
- static void config_fr (sdla_t *card)
- {
- netdevice_t *dev;
- fr_channel_t *chan;
- for (dev=card->wandev.dev; dev; dev=*((netdevice_t **)dev->priv)){
-
- if ((chan=dev->priv) == NULL)
- continue;
-
- if (!test_bit(0,&chan->config_dlci))
- continue;
- clear_bit(0,&chan->config_dlci);
- /* If signalling is set to NO, then setup
- * DLCI addresses right away. Don't have to wait for
- * link to connect.
- */
- if (card->wandev.signalling == WANOPT_NO){
- printk(KERN_INFO "%s: Signalling set to NO: Mapping DLCI'sn",
- card->wandev.name);
- if (fr_init_dlci(card,chan)){
- printk(KERN_INFO "%s: ERROR: Failed to configure DLCI %i !n",
- card->devname, chan->dlci);
- return;
- }
- }
- if (card->wandev.station == WANOPT_CPE) {
-
- update_chan_state(dev);
-
- /* CPE: issue full status enquiry */
- fr_issue_isf(card, FR_ISF_FSE);
- } else {
- /* FR switch: activate DLCI(s) */
-
- /* For Switch emulation we have to ADD and ACTIVATE
- * the DLCI(s) that were configured with the SET_DLCI_
- * CONFIGURATION command. Add and Activate will fail if
- * DLCI specified is not included in the list.
- *
- * Also If_open is called once for each interface. But
- * it does not get in here for all the interface. So
- * we have to pass the entire list of DLCI(s) to add
- * activate routines.
- */
-
- if (!check_dlci_config (card, chan)){
- fr_add_dlci(card, chan->dlci);
- fr_activate_dlci(card, chan->dlci);
- }
- }
- card->u.f.dlci_to_dev_map[chan->dlci] = dev;
- }
- return;
- }
- /*==============================================================
- * config_fr
- *
- * Rationale:
- * All commands must be executed during an interrupt.
- *
- * Description:
- * Trigger uncofig_fr() function through
- * the timer interrupt.
- *
- */
- static void trigger_unconfig_fr (netdevice_t *dev)
- {
- fr_channel_t *chan = dev->priv;
- volatile sdla_t *card = chan->card;
- u32 timeout;
- fr508_flags_t* flags = card->flags;
- int reset_critical=0;
-
- if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){
- clear_bit(PERI_CRIT,(void*)&card->wandev.critical);
- reset_critical=1;
- }
-
- /* run unconfig_dlci() function
- * throught the timer interrupt */
- set_bit(0,(void*)&chan->unconfig_dlci);
- card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UNCONFIG;
- flags->imask |= FR_INTR_TIMER;
- /* Wait for the command to complete */
- timeout = jiffies;
- for(;;) {
- if(!(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG))
- break;
- if ((jiffies - timeout) > (1 * HZ)){
- card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG;
- printk(KERN_INFO "%s: Failed to delete DLCI %in",
- card->devname,chan->dlci);
- break;
- }
- }
- if (reset_critical){
- set_bit(PERI_CRIT,(void*)&card->wandev.critical);
- }
- }
- /*==============================================================
- * unconfig_fr
- *
- * Rationale:
- * All commands must be executed during an interrupt.
- *
- * Description:
- * Remove the dlci from firmware.
- * This funciton is used in NODE shutdown.
- */
- static void unconfig_fr (sdla_t *card)
- {
- netdevice_t *dev;
- fr_channel_t *chan;
- for (dev=card->wandev.dev; dev; dev=*((netdevice_t **)dev->priv)){
-
- if ((chan=dev->priv) == NULL)
- continue;
-
- if (!test_bit(0,&chan->unconfig_dlci))
- continue;
- clear_bit(0,&chan->unconfig_dlci);
- if (card->wandev.station == WANOPT_NODE){
- printk(KERN_INFO "%s: Unconfiguring DLCI %in",
- card->devname,chan->dlci);
- fr_delete_dlci(card,chan->dlci);
- }
- card->u.f.dlci_to_dev_map[chan->dlci] = NULL;
- }
- }
- static int setup_fr_header(struct sk_buff ** skb_orig, netdevice_t* dev, char op_mode)
- {
- struct sk_buff *skb = *skb_orig;
- fr_channel_t *chan=dev->priv;
- if (op_mode == WANPIPE){
- chan->fr_header[0]=Q922_UI;
-
- switch (htons(skb->protocol)){
-
- case ETH_P_IP:
- chan->fr_header[1]=NLPID_IP;
- break;
- default:
- return -EINVAL;
- }
-
- return 2;
- }
- /* If we are in bridging mode, we must apply
- * an Ethernet header */
- if (op_mode == BRIDGE || op_mode == BRIDGE_NODE){
- #if defined(LINUX_2_1) || defined(LINUX_2_4)
- /* Encapsulate the packet as a bridged Ethernet frame. */
- #ifdef DEBUG
- printk(KERN_INFO "%s: encapsulating skb for frame relayn",
- dev->name);
- #endif
-
- chan->fr_header[0] = 0x03;
- chan->fr_header[1] = 0x00;
- chan->fr_header[2] = 0x80;
- chan->fr_header[3] = 0x00;
- chan->fr_header[4] = 0x80;
- chan->fr_header[5] = 0xC2;
- chan->fr_header[6] = 0x00;
- chan->fr_header[7] = 0x07;
- /* Yuck. */
- skb->protocol = ETH_P_802_3;
- return 8;
- #else
- /* BRIDGING is not supported in 2.0.X */
- return -EINVAL;
- #endif
- }
-
- return 0;
- }
- static int check_dlci_config (sdla_t *card, fr_channel_t *chan)
- {
- fr_mbox_t* mbox = card->mbox;
- int err=0;
- fr_conf_t *conf=NULL;
- unsigned short dlci_num = chan->dlci;
- int dlci_offset=0;
- netdevice_t *dev=NULL;
-
- mbox->cmd.command = FR_READ_CONFIG;
- mbox->cmd.length = 0;
- mbox->cmd.dlci = dlci_num;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-
- if (err == CMD_OK){
- return 0;
- }
- for (dev=card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){
- set_chan_state(dev,WAN_DISCONNECTED);
- }
-
- printk(KERN_INFO "DLCI %i Not configured, configuringn",dlci_num);
-
- mbox->cmd.command = FR_COMM_DISABLE;
- mbox->cmd.length = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- if (err != CMD_OK){
- fr_event(card, err, mbox);
- return 2;
- }
- printk(KERN_INFO "Disabled Communications n");
-
- mbox->cmd.command = FR_READ_CONFIG;
- mbox->cmd.length = 0;
- mbox->cmd.dlci = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
-
- if (err != CMD_OK){
- fr_event(card, err, mbox);
- return 2;
- }
-
- conf = (fr_conf_t *)mbox->data;
- dlci_offset=0;
- for (dev=card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){
- fr_channel_t *chan_tmp = dev->priv;
- conf->dlci[dlci_offset] = chan_tmp->dlci;
- dlci_offset++;
- }
-
- printk(KERN_INFO "Got Fr configuration Buffer Length is %x Dlci %i Dlci Off %in",
- mbox->cmd.length,
- mbox->cmd.length > 0x20 ? conf->dlci[0] : -1,
- dlci_offset );
-
- mbox->cmd.length = 0x20 + dlci_offset*2;
- mbox->cmd.command = FR_SET_CONFIG;
- mbox->cmd.dlci = 0;
- err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT;
- if (err != CMD_OK){
- fr_event(card, err, mbox);
- return 2;
- }
- initialize_rx_tx_buffers (card);
-
- printk(KERN_INFO "Configuraiton Succeded for new DLCI %in",dlci_num);
- if (fr_comm_enable (card)){
- return 2;
- }
- printk(KERN_INFO "Enabling Communications n");
- for (dev=card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){
- fr_channel_t *chan_tmp = dev->priv;
- fr_init_dlci(card,chan_tmp);
- fr_add_dlci(card, chan_tmp->dlci);
- fr_activate_dlci(card, chan_tmp->dlci);
- }
- printk(KERN_INFO "END OF CONFIGURAITON %in",dlci_num);
-
- return 1;
- }
- static void initialize_rx_tx_buffers (sdla_t *card)
- {
- fr_buf_info_t* buf_info;
-
- if (card->hw.type == SDLA_S514) {
-
- buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR +
- FR508_RXBC_OFFS);
- card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase);
- card->u.f.rxmb_base =
- (void*)(buf_info->rse_base + card->hw.dpmbase);
- card->u.f.rxmb_last =
- (void*)(buf_info->rse_base +
- (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) +
- card->hw.dpmbase);
- }else{
- buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS);
- card->rxmb = (void*)(buf_info->rse_next -
- FR_MB_VECTOR + card->hw.dpmbase);
-
- card->u.f.rxmb_base =
- (void*)(buf_info->rse_base -
- FR_MB_VECTOR + card->hw.dpmbase);
-
- card->u.f.rxmb_last =
- (void*)(buf_info->rse_base +
- (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) -
- FR_MB_VECTOR + card->hw.dpmbase);
- }
- card->u.f.rx_base = buf_info->buf_base;
- card->u.f.rx_top = buf_info->buf_top;
- card->u.f.tx_interrupts_pending = 0;
- return;
- }
-
- MODULE_LICENSE("GPL");
- /****** End *****************************************************************/