📄 qeth_main.c
字号:
QETH_DBF_TEXT(trace,5,"irqtlet"); channel = (struct qeth_channel *) data; iob = channel->iob; index = channel->buf_no; card = CARD_FROM_CDEV(channel->ccwdev); while (iob[index].state == BUF_STATE_PROCESSED) { if (iob[index].callback !=NULL) { iob[index].callback(channel,iob + index); } index = (index + 1) % QETH_CMD_BUFFER_NO; } channel->buf_no = index; wake_up(&card->wait_q);}static int qeth_stop_card(struct qeth_card *, int);static int__qeth_set_offline(struct ccwgroup_device *cgdev, int recovery_mode){ struct qeth_card *card = (struct qeth_card *) cgdev->dev.driver_data; int rc = 0, rc2 = 0, rc3 = 0; enum qeth_card_states recover_flag; QETH_DBF_TEXT(setup, 3, "setoffl"); QETH_DBF_HEX(setup, 3, &card, sizeof(void *)); netif_carrier_off(card->dev); recover_flag = card->state; if (qeth_stop_card(card, recovery_mode) == -ERESTARTSYS){ PRINT_WARN("Stopping card %s interrupted by user!\n", CARD_BUS_ID(card)); return -ERESTARTSYS; } rc = ccw_device_set_offline(CARD_DDEV(card)); rc2 = ccw_device_set_offline(CARD_WDEV(card)); rc3 = ccw_device_set_offline(CARD_RDEV(card)); if (!rc) rc = (rc2) ? rc2 : rc3; if (rc) QETH_DBF_TEXT_(setup, 2, "1err%d", rc); if (recover_flag == CARD_STATE_UP) card->state = CARD_STATE_RECOVER; qeth_notify_processes(); return 0;}static intqeth_set_offline(struct ccwgroup_device *cgdev){ return __qeth_set_offline(cgdev, 0);}static intqeth_wait_for_threads(struct qeth_card *card, unsigned long threads);static voidqeth_remove_device(struct ccwgroup_device *cgdev){ struct qeth_card *card = (struct qeth_card *) cgdev->dev.driver_data; unsigned long flags; QETH_DBF_TEXT(setup, 3, "rmdev"); QETH_DBF_HEX(setup, 3, &card, sizeof(void *)); if (!card) return; if (qeth_wait_for_threads(card, 0xffffffff)) return; if (cgdev->state == CCWGROUP_ONLINE){ card->use_hard_stop = 1; qeth_set_offline(cgdev); } /* remove form our internal list */ write_lock_irqsave(&qeth_card_list.rwlock, flags); list_del(&card->list); write_unlock_irqrestore(&qeth_card_list.rwlock, flags); if (card->dev) unregister_netdev(card->dev); qeth_remove_device_attributes(&cgdev->dev); qeth_free_card(card); cgdev->dev.driver_data = NULL; put_device(&cgdev->dev);}static intqeth_register_addr_entry(struct qeth_card *, struct qeth_ipaddr *);static intqeth_deregister_addr_entry(struct qeth_card *, struct qeth_ipaddr *);/** * Add/remove address to/from card's ip list, i.e. try to add or remove * reference to/from an IP address that is already registered on the card. * Returns: * 0 address was on card and its reference count has been adjusted, * but is still > 0, so nothing has to be done * also returns 0 if card was not on card and the todo was to delete * the address -> there is also nothing to be done * 1 address was not on card and the todo is to add it to the card's ip * list * -1 address was on card and its reference count has been decremented * to <= 0 by the todo -> address must be removed from card */static int__qeth_ref_ip_on_card(struct qeth_card *card, struct qeth_ipaddr *todo, struct qeth_ipaddr **__addr){ struct qeth_ipaddr *addr; int found = 0; list_for_each_entry(addr, &card->ip_list, entry) { if (card->options.layer2) { if ((addr->type == todo->type) && (memcmp(&addr->mac, &todo->mac, OSA_ADDR_LEN) == 0)) { found = 1; break; } continue; } if ((addr->proto == QETH_PROT_IPV4) && (todo->proto == QETH_PROT_IPV4) && (addr->type == todo->type) && (addr->u.a4.addr == todo->u.a4.addr) && (addr->u.a4.mask == todo->u.a4.mask)) { found = 1; break; } if ((addr->proto == QETH_PROT_IPV6) && (todo->proto == QETH_PROT_IPV6) && (addr->type == todo->type) && (addr->u.a6.pfxlen == todo->u.a6.pfxlen) && (memcmp(&addr->u.a6.addr, &todo->u.a6.addr, sizeof(struct in6_addr)) == 0)) { found = 1; break; } } if (found) { addr->users += todo->users; if (addr->users <= 0){ *__addr = addr; return -1; } else { /* for VIPA and RXIP limit refcount to 1 */ if (addr->type != QETH_IP_TYPE_NORMAL) addr->users = 1; return 0; } } if (todo->users > 0) { /* for VIPA and RXIP limit refcount to 1 */ if (todo->type != QETH_IP_TYPE_NORMAL) todo->users = 1; return 1; } else return 0;}static inline int__qeth_address_exists_in_list(struct list_head *list, struct qeth_ipaddr *addr, int same_type){ struct qeth_ipaddr *tmp; list_for_each_entry(tmp, list, entry) { if ((tmp->proto == QETH_PROT_IPV4) && (addr->proto == QETH_PROT_IPV4) && ((same_type && (tmp->type == addr->type)) || (!same_type && (tmp->type != addr->type)) ) && (tmp->u.a4.addr == addr->u.a4.addr) ){ return 1; } if ((tmp->proto == QETH_PROT_IPV6) && (addr->proto == QETH_PROT_IPV6) && ((same_type && (tmp->type == addr->type)) || (!same_type && (tmp->type != addr->type)) ) && (memcmp(&tmp->u.a6.addr, &addr->u.a6.addr, sizeof(struct in6_addr)) == 0) ) { return 1; } } return 0;}/* * Add IP to be added to todo list. If there is already an "add todo" * in this list we just incremenent the reference count. * Returns 0 if we just incremented reference count. */static int__qeth_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *addr, int add){ struct qeth_ipaddr *tmp, *t; int found = 0; list_for_each_entry_safe(tmp, t, card->ip_tbd_list, entry) { if ((addr->type == QETH_IP_TYPE_DEL_ALL_MC) && (tmp->type == QETH_IP_TYPE_DEL_ALL_MC)) return 0; if (card->options.layer2) { if ((tmp->type == addr->type) && (tmp->is_multicast == addr->is_multicast) && (memcmp(&tmp->mac, &addr->mac, OSA_ADDR_LEN) == 0)) { found = 1; break; } continue; } if ((tmp->proto == QETH_PROT_IPV4) && (addr->proto == QETH_PROT_IPV4) && (tmp->type == addr->type) && (tmp->is_multicast == addr->is_multicast) && (tmp->u.a4.addr == addr->u.a4.addr) && (tmp->u.a4.mask == addr->u.a4.mask)) { found = 1; break; } if ((tmp->proto == QETH_PROT_IPV6) && (addr->proto == QETH_PROT_IPV6) && (tmp->type == addr->type) && (tmp->is_multicast == addr->is_multicast) && (tmp->u.a6.pfxlen == addr->u.a6.pfxlen) && (memcmp(&tmp->u.a6.addr, &addr->u.a6.addr, sizeof(struct in6_addr)) == 0)) { found = 1; break; } } if (found){ if (addr->users != 0) tmp->users += addr->users; else tmp->users += add? 1:-1; if (tmp->users == 0) { list_del(&tmp->entry); kfree(tmp); } return 0; } else { if (addr->type == QETH_IP_TYPE_DEL_ALL_MC) list_add(&addr->entry, card->ip_tbd_list); else { if (addr->users == 0) addr->users += add? 1:-1; if (add && (addr->type == QETH_IP_TYPE_NORMAL) && qeth_is_addr_covered_by_ipato(card, addr)){ QETH_DBF_TEXT(trace, 2, "tkovaddr"); addr->set_flags |= QETH_IPA_SETIP_TAKEOVER_FLAG; } list_add_tail(&addr->entry, card->ip_tbd_list); } return 1; }}/** * Remove IP address from list */static intqeth_delete_ip(struct qeth_card *card, struct qeth_ipaddr *addr){ unsigned long flags; int rc = 0; QETH_DBF_TEXT(trace, 4, "delip"); if (card->options.layer2) QETH_DBF_HEX(trace, 4, &addr->mac, 6); else if (addr->proto == QETH_PROT_IPV4) QETH_DBF_HEX(trace, 4, &addr->u.a4.addr, 4); else { QETH_DBF_HEX(trace, 4, &addr->u.a6.addr, 8); QETH_DBF_HEX(trace, 4, ((char *)&addr->u.a6.addr) + 8, 8); } spin_lock_irqsave(&card->ip_lock, flags); rc = __qeth_insert_ip_todo(card, addr, 0); spin_unlock_irqrestore(&card->ip_lock, flags); return rc;}static intqeth_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr){ unsigned long flags; int rc = 0; QETH_DBF_TEXT(trace, 4, "addip"); if (card->options.layer2) QETH_DBF_HEX(trace, 4, &addr->mac, 6); else if (addr->proto == QETH_PROT_IPV4) QETH_DBF_HEX(trace, 4, &addr->u.a4.addr, 4); else { QETH_DBF_HEX(trace, 4, &addr->u.a6.addr, 8); QETH_DBF_HEX(trace, 4, ((char *)&addr->u.a6.addr) + 8, 8); } spin_lock_irqsave(&card->ip_lock, flags); rc = __qeth_insert_ip_todo(card, addr, 1); spin_unlock_irqrestore(&card->ip_lock, flags); return rc;}static inline void__qeth_delete_all_mc(struct qeth_card *card, unsigned long *flags){ struct qeth_ipaddr *addr, *tmp; int rc;again: list_for_each_entry_safe(addr, tmp, &card->ip_list, entry) { if (addr->is_multicast) { spin_unlock_irqrestore(&card->ip_lock, *flags); rc = qeth_deregister_addr_entry(card, addr); spin_lock_irqsave(&card->ip_lock, *flags); if (!rc) { list_del(&addr->entry); kfree(addr); goto again; } } }}static voidqeth_set_ip_addr_list(struct qeth_card *card){ struct list_head *tbd_list; struct qeth_ipaddr *todo, *addr; unsigned long flags; int rc; QETH_DBF_TEXT(trace, 2, "sdiplist"); QETH_DBF_HEX(trace, 2, &card, sizeof(void *)); spin_lock_irqsave(&card->ip_lock, flags); tbd_list = card->ip_tbd_list; card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC); if (!card->ip_tbd_list) { QETH_DBF_TEXT(trace, 0, "silnomem"); card->ip_tbd_list = tbd_list; spin_unlock_irqrestore(&card->ip_lock, flags); return; } else INIT_LIST_HEAD(card->ip_tbd_list); while (!list_empty(tbd_list)){ todo = list_entry(tbd_list->next, struct qeth_ipaddr, entry); list_del(&todo->entry); if (todo->type == QETH_IP_TYPE_DEL_ALL_MC){ __qeth_delete_all_mc(card, &flags); kfree(todo); continue; } rc = __qeth_ref_ip_on_card(card, todo, &addr); if (rc == 0) { /* nothing to be done; only adjusted refcount */ kfree(todo); } else if (rc == 1) { /* new entry to be added to on-card list */ spin_unlock_irqrestore(&card->ip_lock, flags); rc = qeth_register_addr_entry(card, todo); spin_lock_irqsave(&card->ip_lock, flags); if (!rc) list_add_tail(&todo->entry, &card->ip_list); else kfree(todo); } else if (rc == -1) { /* on-card entry to be removed */ list_del_init(&addr->entry); spin_unlock_irqrestore(&card->ip_lock, flags); rc = qeth_deregister_addr_entry(card, addr); spin_lock_irqsave(&card->ip_lock, flags); if (!rc) kfree(addr); else list_add_tail(&addr->entry, &card->ip_list); kfree(todo); } } spin_unlock_irqrestore(&card->ip_lock, flags); kfree(tbd_list);}static void qeth_delete_mc_addresses(struct qeth_card *);static void qeth_add_multicast_ipv4(struct qeth_card *);static void qeth_layer2_add_multicast(struct qeth_card *);#ifdef CONFIG_QETH_IPV6static void qeth_add_multicast_ipv6(struct qeth_card *);#endifstatic inline intqeth_set_thread_start_bit(struct qeth_card *card, unsigned long thread){ unsigned long flags; spin_lock_irqsave(&card->thread_mask_lock, flags); if ( !(card->thread_allowed_mask & thread) || (card->thread_start_mask & thread) ) { spin_unlock_irqrestore(&card->thread_mask_lock, flags); return -EPERM; } card->thread_start_mask |= thread; spin_unlock_irqrestore(&card->thread_mask_lock, flags); return 0;}static voidqeth_clear_thread_start_bit(struct qeth_card *card, unsigned long thread){ unsigned long flags; spin_lock_irqsave(&card->thread_mask_lock, flags); card->thread_start_mask &= ~thread; spin_unlock_irqrestore(&card->thread_mask_lock, flags); wake_up(&card->wait_q);}static voidqeth_clear_thread_running_bit(struct qeth_card *card, unsigned long thread){ unsigned long flags; spin_lock_irqsave(&card->thread_mask_lock, flags); card->thread_running_mask &= ~thread; spin_unlock_irqrestore(&card->thread_mask_lock, flags); wake_up(&card->wait_q);}static inline int__qeth_do_run_thread(struct qeth_card *card, unsigned long thread){ unsigned long flags; int rc = 0; spin_lock_irqsave(&card->thread_mask_lock, flags); if (card->thread_start_mask & thread){ if ((card->thread_allowed_mask & thread) && !(card->thread_running_mask & thread)){ rc = 1; card->thread_start_mask &= ~thread; card->thread_running_mask |= thread; } else rc = -EPERM; } spin_unlock_irqrestore(&card->thread_mask_lock, flags); return rc;}static intqeth_do_run_thread(struct qeth_card *card, unsigned long thread){ int rc = 0; wait_event(card->wait_q, (rc = __qeth_do_run_thread(card, thread)) >= 0); return rc;}static intqeth_register_ip_addresses(void *ptr){ struct qeth_card *card; card = (struct qeth_card *) ptr; daemonize("qeth_reg_ip"); QETH_DBF_TEXT(trace,4,"regipth1"); if (!qeth_do_run_thread(card, QETH_SET_IP_THREAD)) return 0; QETH_DBF_TEXT(trace,4,"regipth2"); qeth_set_ip_addr_list(card); qeth_clear_thread_running_bit(card, QETH_SET_IP_THREAD); return 0;}/* * Drive the SET_PROMISC_MODE thread */static intqeth_set_promisc_mode(void *ptr){ struct qeth_card *card = (struct qeth_card *) ptr; daemonize("qeth_setprm"); QETH_DBF_TEXT(trace,4,"setprm1"); if (!qeth_do_run_thread(card, QETH_SET_PROMISC_MODE_THREAD)) return 0; QETH_DBF_TEXT(trace,4,"setprm2"); qeth_setadp_promisc_mode(card); qeth_clear_thread_running_bit(card, QETH_SET_PROMISC_MODE_THREAD); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -