X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fs390%2Fnet%2Fqeth_main.c;h=535f46b92d72f0e4bea5851e8ac971e9b9c60ee2;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=3e374ddfe78034da006df4dc386f22bf1ea6338c;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 3e374ddfe..535f46b92 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/qeth_main.c ($Revision: 1.145 $) + * linux/drivers/s390/net/qeth_main.c ($Revision: 1.191 $) * * Linux on zSeries OSA Express and HiperSockets support * @@ -12,7 +12,7 @@ * Frank Pavlic (pavlic@de.ibm.com) and * Thomas Spatzier * - * $Revision: 1.145 $ $Date: 2004/10/08 15:08:40 $ + * $Revision: 1.191 $ $Date: 2005/01/31 13:13:57 $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,7 +29,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - /*** * eye catcher; just for debugging purposes */ @@ -42,16 +41,9 @@ qeth_eyecatcher(void) #include #include #include - #include #include #include - -#include -#include -#include -#include -#include #include #include #include @@ -63,23 +55,29 @@ qeth_eyecatcher(void) #include #include #include -#include -#include #include #include -#include -#include #include #include -#include #include #include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + #include "qeth.h" #include "qeth_mpc.h" #include "qeth_fs.h" -#define VERSION_QETH_C "$Revision: 1.145 $" +#define VERSION_QETH_C "$Revision: 1.191 $" static const char *version = "qeth S/390 OSA-Express driver"; /** @@ -160,6 +158,9 @@ qeth_set_online(struct ccwgroup_device *); static struct qeth_ipaddr * qeth_get_addr_buffer(enum qeth_prot_versions); +static void +qeth_set_multicast_list(struct net_device *); + static void qeth_notify_processes(void) { @@ -197,7 +198,7 @@ qeth_notifier_register(struct task_struct *p, int signum) { struct qeth_notify_list_struct *n_entry; - QETH_DBF_TEXT(trace, 2, "notreg"); + /*check first if entry already exists*/ spin_lock(&qeth_notify_lock); list_for_each_entry(n_entry, &qeth_notify_list, list) { @@ -250,6 +251,7 @@ qeth_free_card(struct qeth_card *card) free_netdev(card->dev); qeth_clear_ip_list(card, 0, 0); qeth_clear_ipato_list(card); + kfree(card->ip_tbd_list); qeth_free_qdio_buffers(card); kfree(card); } @@ -511,6 +513,7 @@ static int qeth_set_offline(struct ccwgroup_device *cgdev) { struct qeth_card *card = (struct qeth_card *) cgdev->dev.driver_data; + int rc = 0; enum qeth_card_states recover_flag; QETH_DBF_TEXT(setup, 3, "setoffl"); @@ -522,15 +525,21 @@ qeth_set_offline(struct ccwgroup_device *cgdev) CARD_BUS_ID(card)); return -ERESTARTSYS; } - ccw_device_set_offline(CARD_DDEV(card)); - ccw_device_set_offline(CARD_WDEV(card)); - ccw_device_set_offline(CARD_RDEV(card)); + if ((rc = ccw_device_set_offline(CARD_DDEV(card))) || + (rc = ccw_device_set_offline(CARD_WDEV(card))) || + (rc = ccw_device_set_offline(CARD_RDEV(card)))) { + 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 int +qeth_wait_for_threads(struct qeth_card *card, unsigned long threads); + + static void qeth_remove_device(struct ccwgroup_device *cgdev) { @@ -543,6 +552,9 @@ qeth_remove_device(struct ccwgroup_device *cgdev) 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); @@ -618,7 +630,7 @@ __qeth_ref_ip_on_card(struct qeth_card *card, struct qeth_ipaddr *todo, if (todo->users > 0){ /* for VIPA and RXIP limit refcount to 1 */ if (todo->type != QETH_IP_TYPE_NORMAL) - addr->users = 1; + todo->users = 1; return 1; } else return 0; @@ -661,7 +673,10 @@ __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) { + 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 ((tmp->proto == QETH_PROT_IPV4) && (addr->proto == QETH_PROT_IPV4) && (tmp->type == addr->type) && @@ -693,14 +708,18 @@ __qeth_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *addr, int add) } return 0; } 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; + 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); } - list_add_tail(&addr->entry, &card->ip_tbd_list); return 1; } } @@ -718,8 +737,8 @@ qeth_delete_ip(struct qeth_card *card, struct qeth_ipaddr *addr) 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,4); - QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+4,4); + 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); @@ -737,8 +756,8 @@ qeth_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr) 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,4); - QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+4,4); + 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); @@ -746,19 +765,21 @@ qeth_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr) return rc; } -static void -qeth_reinsert_todos(struct qeth_card *card, struct list_head *todos) +static inline void +__qeth_delete_all_mc(struct qeth_card *card, unsigned long *flags) { - struct qeth_ipaddr *todo, *tmp; + struct qeth_ipaddr *addr, *tmp; + int rc; - list_for_each_entry_safe(todo, tmp, todos, entry){ - list_del_init(&todo->entry); - if (todo->users < 0) { - if (!qeth_delete_ip(card, todo)) - kfree(todo); - } else { - if (!qeth_add_ip(card, todo)) - kfree(todo); + 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); + } } } } @@ -766,7 +787,7 @@ qeth_reinsert_todos(struct qeth_card *card, struct list_head *todos) static void qeth_set_ip_addr_list(struct qeth_card *card) { - struct list_head failed_todos; + struct list_head *tbd_list; struct qeth_ipaddr *todo, *addr; unsigned long flags; int rc; @@ -774,13 +795,25 @@ qeth_set_ip_addr_list(struct qeth_card *card) QETH_DBF_TEXT(trace, 2, "sdiplist"); QETH_DBF_HEX(trace, 2, &card, sizeof(void *)); - INIT_LIST_HEAD(&failed_todos); - spin_lock_irqsave(&card->ip_lock, flags); - while (!list_empty(&card->ip_tbd_list)) { - todo = list_entry(card->ip_tbd_list.next, - struct qeth_ipaddr, entry); - list_del_init(&todo->entry); + 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 */ @@ -793,24 +826,22 @@ qeth_set_ip_addr_list(struct qeth_card *card) if (!rc) list_add_tail(&todo->entry, &card->ip_list); else - list_add_tail(&todo->entry, &failed_todos); + 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) { + if (!rc) kfree(addr); - kfree(todo); - } else { + else list_add_tail(&addr->entry, &card->ip_list); - list_add_tail(&todo->entry, &failed_todos); - } + kfree(todo); } } spin_unlock_irqrestore(&card->ip_lock, flags); - qeth_reinsert_todos(card, &failed_todos); + kfree(tbd_list); } static void qeth_delete_mc_addresses(struct qeth_card *); @@ -888,28 +919,7 @@ qeth_do_run_thread(struct qeth_card *card, unsigned long thread) } static int -qeth_register_mc_addresses(void *ptr) -{ - struct qeth_card *card; - - card = (struct qeth_card *) ptr; - daemonize("qeth_reg_mcaddrs"); - QETH_DBF_TEXT(trace,4,"regmcth1"); - if (!qeth_do_run_thread(card, QETH_SET_MC_THREAD)) - return 0; - QETH_DBF_TEXT(trace,4,"regmcth2"); - qeth_delete_mc_addresses(card); - qeth_add_multicast_ipv4(card); -#ifdef CONFIG_QETH_IPV6 - qeth_add_multicast_ipv6(card); -#endif - qeth_set_ip_addr_list(card); - qeth_clear_thread_running_bit(card, QETH_SET_MC_THREAD); - return 0; -} - -static int -qeth_register_ip_address(void *ptr) +qeth_register_ip_addresses(void *ptr) { struct qeth_card *card; @@ -989,9 +999,7 @@ qeth_start_kernel_thread(struct qeth_card *card) return; if (qeth_do_start_thread(card, QETH_SET_IP_THREAD)) - kernel_thread(qeth_register_ip_address, (void *) card, SIGCHLD); - if (qeth_do_start_thread(card, QETH_SET_MC_THREAD)) - kernel_thread(qeth_register_mc_addresses, (void *)card,SIGCHLD); + kernel_thread(qeth_register_ip_addresses, (void *)card,SIGCHLD); if (qeth_do_start_thread(card, QETH_RECOVER_THREAD)) kernel_thread(qeth_recover, (void *) card, SIGCHLD); } @@ -1010,6 +1018,7 @@ qeth_set_intial_options(struct qeth_card *card) card->options.fake_broadcast = 0; card->options.add_hhlen = DEFAULT_ADD_HHLEN; card->options.fake_ll = 0; + card->options.layer2 = 0; } /** @@ -1041,7 +1050,12 @@ qeth_setup_card(struct qeth_card *card) INIT_WORK(&card->kernel_thread_starter, (void *)qeth_start_kernel_thread,card); INIT_LIST_HEAD(&card->ip_list); - INIT_LIST_HEAD(&card->ip_tbd_list); + card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL); + if (!card->ip_tbd_list) { + QETH_DBF_TEXT(setup, 0, "iptbdnom"); + return -ENOMEM; + } + INIT_LIST_HEAD(card->ip_tbd_list); INIT_LIST_HEAD(&card->cmd_waiter_list); init_waitqueue_head(&card->wait_q); /* intial options */ @@ -1306,6 +1320,7 @@ qeth_idx_activate_get_answer(struct qeth_channel *channel, if (channel->state != CH_STATE_UP){ rc = -ETIME; QETH_DBF_TEXT_(setup, 2, "3err%d", rc); + qeth_clear_cmd_buffers(channel); } else rc = 0; return rc; @@ -1372,6 +1387,7 @@ qeth_idx_activate_channel(struct qeth_channel *channel, if (channel->state != CH_STATE_ACTIVATING) { PRINT_WARN("qeth: IDX activate timed out!\n"); QETH_DBF_TEXT_(setup, 2, "2err%d", -ETIME); + qeth_clear_cmd_buffers(channel); return -ETIME; } return qeth_idx_activate_get_answer(channel,idx_reply_cb); @@ -1575,9 +1591,8 @@ qeth_reset_ip_addresses(struct qeth_card *card) QETH_DBF_TEXT(trace, 2, "rstipadd"); qeth_clear_ip_list(card, 0, 1); - if ( (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0) || - (qeth_set_thread_start_bit(card, QETH_SET_MC_THREAD) == 0) ) - schedule_work(&card->kernel_thread_starter); + /* this function will also schedule the SET_IP_THREAD */ + qeth_set_multicast_list(card->dev); } static struct qeth_ipa_cmd * @@ -1597,25 +1612,19 @@ qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob) "there is a network problem or " "someone pulled the cable or " "disabled the port.\n", - card->info.if_name, + QETH_CARD_IFNAME(card), card->info.chpid); card->lan_online = 0; - if (netif_carrier_ok(card->dev)) { - netif_carrier_off(card->dev); - netif_stop_queue(card->dev); - } + netif_carrier_off(card->dev); return NULL; case IPA_CMD_STARTLAN: PRINT_INFO("Link reestablished on %s " "(CHPID 0x%X). Scheduling " "IP address reset.\n", - card->info.if_name, + QETH_CARD_IFNAME(card), card->info.chpid); card->lan_online = 1; - if (!netif_carrier_ok(card->dev)) { - netif_carrier_on(card->dev); - netif_wake_queue(card->dev); - } + netif_carrier_on(card->dev); qeth_reset_ip_addresses(card); return NULL; case IPA_CMD_REGISTER_LOCAL_ADDR: @@ -1624,7 +1633,7 @@ qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob) case IPA_CMD_UNREGISTER_LOCAL_ADDR: PRINT_WARN("probably problem on %s: " "received IPA command 0x%X\n", - card->info.if_name, + QETH_CARD_IFNAME(card), cmd->hdr.command); break; default: @@ -1815,10 +1824,18 @@ qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, void *reply_param) { int rc; + char prot_type; QETH_DBF_TEXT(trace,4,"sendipa"); memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); + + if (card->options.layer2) + prot_type = QETH_PROT_LAYER2; + else + prot_type = QETH_PROT_TCPIP; + + memcpy(QETH_IPA_CMD_PROT_TYPE(iob->data),&prot_type,1); memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data), &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH); @@ -1951,6 +1968,7 @@ static int qeth_ulp_enable(struct qeth_card *card) { int rc; + char prot_type; struct qeth_cmd_buffer *iob; /*FIXME: trace view callbacks*/ @@ -1961,7 +1979,12 @@ qeth_ulp_enable(struct qeth_card *card) *(QETH_ULP_ENABLE_LINKNUM(iob->data)) = (__u8) card->info.portno; + if (card->options.layer2) + prot_type = QETH_PROT_LAYER2; + else + prot_type = QETH_PROT_TCPIP; + memcpy(QETH_ULP_ENABLE_PROT_TYPE(iob->data),&prot_type,1); memcpy(QETH_ULP_ENABLE_DEST_ADDR(iob->data), &card->token.cm_connection_r, QETH_MPC_TOKEN_LENGTH); memcpy(QETH_ULP_ENABLE_FILTER_TOKEN(iob->data), @@ -2084,7 +2107,11 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, *hdr = element->addr + offset; offset += sizeof(struct qeth_hdr); - skb_len = (*hdr)->length; + if (card->options.layer2) + skb_len = (*hdr)->hdr.l2.pkt_length; + else + skb_len = (*hdr)->hdr.l3.length; + if (!skb_len) return NULL; if (card->options.fake_ll){ @@ -2123,7 +2150,7 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, no_mem: if (net_ratelimit()){ PRINT_WARN("No memory for packet received on %s.\n", - card->info.if_name); + QETH_CARD_IFNAME(card)); QETH_DBF_TEXT(trace,2,"noskbmem"); QETH_DBF_TEXT_(trace,2,"%s",CARD_BUS_ID(card)); } @@ -2134,10 +2161,10 @@ no_mem: static inline unsigned short qeth_type_trans(struct sk_buff *skb, struct net_device *dev) { - struct ethhdr *eth; struct qeth_card *card; + struct ethhdr *eth; - QETH_DBF_TEXT(trace,5,"typtrans"); + QETH_DBF_TEXT(trace,6,"typtrans"); card = (struct qeth_card *)dev->priv; #ifdef CONFIG_TR @@ -2145,9 +2172,8 @@ qeth_type_trans(struct sk_buff *skb, struct net_device *dev) (card->info.link_type == QETH_LINK_TYPE_LANE_TR)) return tr_type_trans(skb,dev); #endif /* CONFIG_TR */ - skb->mac.raw = skb->data; - skb_pull(skb, ETH_ALEN * 2 + sizeof (short)); + skb_pull(skb, ETH_HLEN ); eth = eth_hdr(skb); if (*eth->h_dest & 1) { @@ -2155,9 +2181,9 @@ qeth_type_trans(struct sk_buff *skb, struct net_device *dev) skb->pkt_type = PACKET_BROADCAST; else skb->pkt_type = PACKET_MULTICAST; - } else { + } else if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN)) skb->pkt_type = PACKET_OTHERHOST; - } + if (ntohs(eth->h_proto) >= 1536) return eth->h_proto; if (*(unsigned short *) (skb->data) == 0xFFFF) @@ -2206,8 +2232,8 @@ qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb, memcpy(fake_hdr->h_dest, card->dev->dev_addr, ETH_ALEN); } /* the source MAC address */ - if (hdr->ext_flags & QETH_HDR_EXT_SRC_MAC_ADDR) - memcpy(fake_hdr->h_source, &hdr->dest_addr[2], ETH_ALEN); + if (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_SRC_MAC_ADDR) + memcpy(fake_hdr->h_source, &hdr->hdr.l3.dest_addr[2], ETH_ALEN); else memset(fake_hdr->h_source, 0, ETH_ALEN); /* the protocol */ @@ -2221,28 +2247,52 @@ qeth_rebuild_skb_vlan(struct qeth_card *card, struct sk_buff *skb, #ifdef CONFIG_QETH_VLAN u16 *vlan_tag; - if (hdr->ext_flags & QETH_HDR_EXT_VLAN_FRAME) { + if (hdr->hdr.l3.ext_flags & + (QETH_HDR_EXT_VLAN_FRAME | QETH_HDR_EXT_INCLUDE_VLAN_TAG)) { vlan_tag = (u16 *) skb_push(skb, VLAN_HLEN); - *vlan_tag = hdr->vlan_id; + *vlan_tag = (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_VLAN_FRAME)? + hdr->hdr.l3.vlan_id : *((u16 *)&hdr->hdr.l3.dest_addr[12]); *(vlan_tag + 1) = skb->protocol; skb->protocol = __constant_htons(ETH_P_8021Q); } #endif /* CONFIG_QETH_VLAN */ } +static inline __u16 +qeth_layer2_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, + struct qeth_hdr *hdr) +{ + unsigned short vlan_id = 0; + + skb->pkt_type = PACKET_HOST; + if (card->options.checksum_type == NO_CHECKSUMMING) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; +#ifdef CONFIG_QETH_VLAN + if (hdr->hdr.l2.flags[2] & (QETH_LAYER2_FLAG_VLAN)) { + vlan_id = hdr->hdr.l2.vlan_id; + skb_pull(skb, VLAN_HLEN); + } +#endif + skb->protocol = qeth_type_trans(skb, skb->dev); + return vlan_id; +} + static inline void qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr *hdr) { #ifdef CONFIG_QETH_IPV6 - if (hdr->flags & QETH_HDR_PASSTHRU){ + if (hdr->hdr.l3.flags & QETH_HDR_PASSTHRU) { + skb->pkt_type = PACKET_HOST; skb->protocol = qeth_type_trans(skb, card->dev); return; } #endif /* CONFIG_QETH_IPV6 */ - skb->protocol = htons((hdr->flags & QETH_HDR_IPV6)? ETH_P_IPV6 : + skb->protocol = htons((hdr->hdr.l3.flags & QETH_HDR_IPV6)? ETH_P_IPV6 : ETH_P_IP); - switch (hdr->flags & QETH_HDR_CAST_MASK){ + switch (hdr->hdr.l3.flags & QETH_HDR_CAST_MASK){ case QETH_CAST_UNICAST: skb->pkt_type = PACKET_HOST; break; @@ -2259,13 +2309,14 @@ qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, default: skb->pkt_type = PACKET_HOST; } + qeth_rebuild_skb_vlan(card, skb, hdr); if (card->options.fake_ll) qeth_rebuild_skb_fake_ll(card, skb, hdr); else skb->mac.raw = skb->data; skb->ip_summed = card->options.checksum_type; if (card->options.checksum_type == HW_CHECKSUMMING){ - if ( (hdr->ext_flags & + if ( (hdr->hdr.l3.ext_flags & (QETH_HDR_EXT_CSUM_HDR_REQ | QETH_HDR_EXT_CSUM_TRANSP_REQ)) == (QETH_HDR_EXT_CSUM_HDR_REQ | @@ -2274,7 +2325,6 @@ qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, else skb->ip_summed = SW_CHECKSUMMING; } - qeth_rebuild_skb_vlan(card, skb, hdr); } static inline void @@ -2282,10 +2332,11 @@ qeth_process_inbound_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf, int index) { struct qdio_buffer_element *element; - int offset; struct sk_buff *skb; struct qeth_hdr *hdr; + int offset; int rxrc; + __u16 vlan_tag = 0; /* get first element of current buffer */ element = (struct qdio_buffer_element *)&buf->buffer->element[0]; @@ -2294,14 +2345,22 @@ qeth_process_inbound_buffer(struct qeth_card *card, card->perf_stats.bufs_rec++; #endif while((skb = qeth_get_next_skb(card, buf->buffer, &element, - &offset, &hdr))){ - qeth_rebuild_skb(card, skb, hdr); + &offset, &hdr))) { + skb->dev = card->dev; + if (hdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) + vlan_tag = qeth_layer2_rebuild_skb(card, skb, hdr); + else + qeth_rebuild_skb(card, skb, hdr); /* is device UP ? */ if (!(card->dev->flags & IFF_UP)){ dev_kfree_skb_any(skb); continue; } - skb->dev = card->dev; +#ifdef CONFIG_QETH_VLAN + if (vlan_tag) + vlan_hwaccel_rx(skb, card->vlangrp, vlan_tag); + else +#endif rxrc = netif_rx(skb); card->dev->last_rx = jiffies; card->stats.rx_packets++; @@ -2759,7 +2818,8 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status, } atomic_sub(count, &queue->used_buffers); /* check if we need to do something on this outbound queue */ - qeth_check_outbound_queue(queue); + if (card->info.type != QETH_CARD_TYPE_IQD) + qeth_check_outbound_queue(queue); netif_wake_queue(card->dev); #ifdef CONFIG_QETH_PERF_STATS @@ -3211,13 +3271,15 @@ qeth_qdio_clear_card(struct qeth_card *card, int use_halt) QETH_DBF_TEXT(trace,3,"qdioclr"); if (card->qdio.state == QETH_QDIO_ESTABLISHED){ - qdio_cleanup(CARD_DDEV(card), + if ((rc = qdio_cleanup(CARD_DDEV(card), (card->info.type == QETH_CARD_TYPE_IQD) ? QDIO_FLAG_CLEANUP_USING_HALT : - QDIO_FLAG_CLEANUP_USING_CLEAR); + QDIO_FLAG_CLEANUP_USING_CLEAR))) + QETH_DBF_TEXT_(trace, 3, "1err%d", rc); card->qdio.state = QETH_QDIO_ALLOCATED; } - rc = qeth_clear_halt_card(card, use_halt); + if ((rc = qeth_clear_halt_card(card, use_halt))) + QETH_DBF_TEXT_(trace, 3, "2err%d", rc); card->state = CARD_STATE_DOWN; return rc; } @@ -3319,6 +3381,26 @@ qeth_get_netdevice(enum qeth_card_types type, enum qeth_link_types linktype) return dev; } +/*hard_header fake function; used in case fake_ll is set */ +static int +qeth_fake_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, + unsigned len) +{ + struct ethhdr *hdr; + struct qeth_card *card; + + card = (struct qeth_card *)dev->priv; + hdr = (struct ethhdr *)skb_push(skb, QETH_FAKE_LL_LEN); + memcpy(hdr->h_source, card->dev->dev_addr, ETH_ALEN); + memcpy(hdr->h_dest, "FAKELL", ETH_ALEN); + if (type != ETH_P_802_3) + hdr->h_proto = htons(type); + else + hdr->h_proto = htons(len); + return QETH_FAKE_LL_LEN; +} + static inline int qeth_send_packet(struct qeth_card *, struct sk_buff *); @@ -3333,25 +3415,46 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (skb==NULL) { card->stats.tx_dropped++; card->stats.tx_errors++; - return -EIO; + /* return OK; otherwise ksoftirqd goes to 100% */ + return NETDEV_TX_OK; } - if ((card->state != CARD_STATE_UP) || !netif_carrier_ok(dev)) { + if ((card->state != CARD_STATE_UP) || !card->lan_online) { card->stats.tx_dropped++; card->stats.tx_errors++; card->stats.tx_carrier_errors++; - return -EIO; + dev_kfree_skb_any(skb); + /* return OK; otherwise ksoftirqd goes to 100% */ + return NETDEV_TX_OK; } #ifdef CONFIG_QETH_PERF_STATS card->perf_stats.outbound_cnt++; card->perf_stats.outbound_start_time = qeth_get_micros(); #endif + if (dev->hard_header == qeth_fake_header) { + if ((skb = qeth_pskb_unshare(skb, GFP_ATOMIC)) == NULL) { + card->stats.tx_dropped++; + dev_kfree_skb_irq(skb); + return 0; + } + skb_pull(skb, QETH_FAKE_LL_LEN); + } /* * We only call netif_stop_queue in case of errors. Since we've * got our own synchronization on queues we can keep the stack's * queue running. */ - if ((rc = qeth_send_packet(card, skb))) - netif_stop_queue(dev); + if ((rc = qeth_send_packet(card, skb))){ + if (rc == -EBUSY) { + netif_stop_queue(dev); + rc = NETDEV_TX_BUSY; + } else { + card->stats.tx_errors++; + card->stats.tx_dropped++; + dev_kfree_skb_any(skb); + /* set to OK; otherwise ksoftirqd goes to 100% */ + rc = NETDEV_TX_OK; + } + } #ifdef CONFIG_QETH_PERF_STATS card->perf_stats.outbound_time += qeth_get_micros() - @@ -3442,6 +3545,11 @@ qeth_open(struct net_device *dev) if (card->state != CARD_STATE_SOFTSETUP) return -ENODEV; + if ( (card->options.layer2) && + (!card->info.layer2_mac_registered)) { + QETH_DBF_TEXT(trace,4,"nomacadr"); + return -EPERM; + } card->dev->flags |= IFF_UP; netif_start_queue(dev); card->data.state = CH_STATE_UP; @@ -3450,7 +3558,6 @@ qeth_open(struct net_device *dev) if (!card->lan_online){ if (netif_carrier_ok(dev)) netif_carrier_off(dev); - netif_stop_queue(dev); } return 0; } @@ -3491,12 +3598,12 @@ qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb) else if (skb->protocol == ETH_P_IP) return ((skb->nh.raw[16] & 0xf0) == 0xe0) ? RTN_MULTICAST : 0; /* ... */ - if (!memcmp(skb->nh.raw, skb->dev->broadcast, 6)) + if (!memcmp(skb->data, skb->dev->broadcast, 6)) return RTN_BROADCAST; else { u16 hdr_mac; - hdr_mac = *((u16 *)skb->nh.raw); + hdr_mac = *((u16 *)skb->data); /* tr multicast? */ switch (card->info.link_type) { case QETH_LINK_TYPE_HSTR: @@ -3575,13 +3682,14 @@ qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb, if (!new_skb) { PRINT_ERR("qeth_prepare_skb: could " "not realloc headroom for qeth_hdr " - "on interface %s", card->info.if_name); + "on interface %s", QETH_CARD_IFNAME(card)); return -ENOMEM; } *skb = new_skb; } #ifdef CONFIG_QETH_VLAN - if (card->vlangrp && vlan_tx_tag_present(*skb) && (ipv == 6)){ + if (card->vlangrp && vlan_tx_tag_present(*skb) && + ((ipv == 6) || card->options.layer2) ) { /* * Move the mac addresses (6 bytes src, 6 bytes dest) * to the beginning of the new header. We are using three @@ -3591,14 +3699,13 @@ qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb, memcpy((*skb)->data, (*skb)->data + 4, 4); memcpy((*skb)->data + 4, (*skb)->data + 8, 4); memcpy((*skb)->data + 8, (*skb)->data + 12, 4); - tag = (u16 *) (*skb)->data + 12; + tag = (u16 *)((*skb)->data + 12); /* * first two bytes = ETH_P_8021Q (0x8100) * second two bytes = VLANID */ *tag = __constant_htons(ETH_P_8021Q); - *(tag + 1) = vlan_tx_tag_get(*skb); - *(tag + 1) = htons(*(tag + 1)); + *(tag + 1) = htons(vlan_tx_tag_get(*skb)); } #endif *hdr = (struct qeth_hdr *) skb_push(*skb, sizeof(struct qeth_hdr)); @@ -3612,7 +3719,7 @@ qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb, QETH_IP_HEADER_SIZE) & (~(PAGE_SIZE - 1)))) { PRINT_ERR("qeth_prepare_skb: misaligned " "packet on interface %s. Discarded.", - card->info.if_name); + QETH_CARD_IFNAME(card)); return -EINVAL; } return 0; @@ -3641,51 +3748,121 @@ qeth_get_qeth_hdr_flags6(int cast_type) return ct | QETH_CAST_UNICAST; } +static inline void +qeth_layer2_get_packet_type(struct qeth_card *card, struct qeth_hdr *hdr, + struct sk_buff *skb) +{ + __u16 hdr_mac; + + if (!memcmp(skb->data+QETH_HEADER_SIZE, + skb->dev->broadcast,6)) { /* broadcast? */ + *(__u32 *)hdr->hdr.l2.flags |= + QETH_LAYER2_FLAG_BROADCAST << 8; + return; + } + hdr_mac=*((__u16*)skb->data); + /* tr multicast? */ + switch (card->info.link_type) { + case QETH_LINK_TYPE_HSTR: + case QETH_LINK_TYPE_LANE_TR: + if ((hdr_mac == QETH_TR_MAC_NC) || + (hdr_mac == QETH_TR_MAC_C) ) + *(__u32 *)hdr->hdr.l2.flags |= + QETH_LAYER2_FLAG_MULTICAST << 8; + else + *(__u32 *)hdr->hdr.l2.flags |= + QETH_LAYER2_FLAG_UNICAST << 8; + break; + /* eth or so multicast? */ + default: + if ( (hdr_mac==QETH_ETH_MAC_V4) || + (hdr_mac==QETH_ETH_MAC_V6) ) + *(__u32 *)hdr->hdr.l2.flags |= + QETH_LAYER2_FLAG_MULTICAST << 8; + else + *(__u32 *)hdr->hdr.l2.flags |= + QETH_LAYER2_FLAG_UNICAST << 8; + } +} + +static inline void +qeth_layer2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, + struct sk_buff *skb, int cast_type) +{ + memset(hdr, 0, sizeof(struct qeth_hdr)); + hdr->hdr.l2.id = QETH_HEADER_TYPE_LAYER2; + + /* set byte 0 to "0x02" and byte 3 to casting flags */ + if (cast_type==RTN_MULTICAST) + *(__u32 *)hdr->hdr.l2.flags |= QETH_LAYER2_FLAG_MULTICAST << 8; + else if (cast_type==RTN_BROADCAST) + *(__u32 *)hdr->hdr.l2.flags |= QETH_LAYER2_FLAG_BROADCAST << 8; + else + qeth_layer2_get_packet_type(card, hdr, skb); + + hdr->hdr.l2.pkt_length = skb->len-QETH_HEADER_SIZE; +#ifdef CONFIG_QETH_VLAN + /* VSWITCH relies on the VLAN + * information to be present in + * the QDIO header */ + if ((card->vlangrp != NULL) && + vlan_tx_tag_present(skb)) { + *(__u32 *)hdr->hdr.l2.flags |= QETH_LAYER2_FLAG_VLAN << 8; + hdr->hdr.l2.vlan_id = vlan_tx_tag_get(skb); + } +#endif +} + static inline void qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, struct sk_buff *skb, int ipv, int cast_type) { - hdr->id = 1; - hdr->ext_flags = 0; - QETH_DBF_TEXT(trace, 6, "fillhdr"); + + if (card->options.layer2) { + qeth_layer2_fill_header(card, hdr, skb, cast_type); + return; + } + hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; + hdr->hdr.l3.ext_flags = 0; #ifdef CONFIG_QETH_VLAN /* * before we're going to overwrite this location with next hop ip. * v6 uses passthrough, v4 sets the tag in the QDIO header. */ if (card->vlangrp && vlan_tx_tag_present(skb)) { - hdr->ext_flags = (ipv == 4)? QETH_EXT_HDR_VLAN_FRAME : - QETH_EXT_HDR_INCLUDE_VLAN_TAG; - hdr->vlan_id = vlan_tx_tag_get(skb); + hdr->hdr.l3.ext_flags = (ipv == 4) ? + QETH_HDR_EXT_VLAN_FRAME : + QETH_HDR_EXT_INCLUDE_VLAN_TAG; + hdr->hdr.l3.vlan_id = vlan_tx_tag_get(skb); } #endif /* CONFIG_QETH_VLAN */ - hdr->length = skb->len - sizeof(struct qeth_hdr); + hdr->hdr.l3.length = skb->len - sizeof(struct qeth_hdr); if (ipv == 4) { /* IPv4 */ - hdr->flags = qeth_get_qeth_hdr_flags4(cast_type); - memset(hdr->dest_addr, 0, 12); + hdr->hdr.l3.flags = qeth_get_qeth_hdr_flags4(cast_type); + memset(hdr->hdr.l3.dest_addr, 0, 12); if ((skb->dst) && (skb->dst->neighbour)) { - *((u32 *) (&hdr->dest_addr[12])) = + *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = *((u32 *) skb->dst->neighbour->primary_key); } else { /* fill in destination address used in ip header */ - *((u32 *) (&hdr->dest_addr[12])) = skb->nh.iph->daddr; + *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = skb->nh.iph->daddr; } } else if (ipv == 6) { /* IPv6 or passthru */ - hdr->flags = qeth_get_qeth_hdr_flags6(cast_type); + hdr->hdr.l3.flags = qeth_get_qeth_hdr_flags6(cast_type); if ((skb->dst) && (skb->dst->neighbour)) { - memcpy(hdr->dest_addr, + memcpy(hdr->hdr.l3.dest_addr, skb->dst->neighbour->primary_key, 16); } else { /* fill in destination address used in ip header */ - memcpy(hdr->dest_addr, &skb->nh.ipv6h->daddr, 16); + memcpy(hdr->hdr.l3.dest_addr, &skb->nh.ipv6h->daddr, 16); } } else { /* passthrough */ if (!memcmp(skb->data + sizeof(struct qeth_hdr), skb->dev->broadcast, 6)) { /* broadcast? */ - hdr->flags = QETH_CAST_BROADCAST | QETH_HDR_PASSTHRU; + hdr->hdr.l3.flags = QETH_CAST_BROADCAST | QETH_HDR_PASSTHRU; } else { - hdr->flags = (cast_type == RTN_MULTICAST) ? + hdr->hdr.l3.flags = (cast_type == RTN_MULTICAST) ? QETH_CAST_MULTICAST | QETH_HDR_PASSTHRU : QETH_CAST_UNICAST | QETH_HDR_PASSTHRU; } @@ -3874,7 +4051,7 @@ out: static inline int qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) { - int ipv; + int ipv = 0; int cast_type; struct qeth_qdio_out_q *queue; struct qeth_hdr *hdr; @@ -3883,7 +4060,8 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) QETH_DBF_TEXT(trace, 6, "sendpkt"); - ipv = qeth_get_ip_version(skb); + if (!card->options.layer2) + ipv = qeth_get_ip_version(skb); cast_type = qeth_get_cast_type(card, skb); queue = card->qdio.out_qs [qeth_get_priority_queue(card, skb, ipv, cast_type)]; @@ -4048,7 +4226,7 @@ qeth_arp_set_no_entries(struct qeth_card *card, int no_entries) return -EOPNOTSUPP; if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) { PRINT_WARN("ARP processing not supported " - "on %s!\n", card->info.if_name); + "on %s!\n", QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } rc = qeth_send_simple_setassparms(card, IPA_ARP_PROCESSING, @@ -4058,7 +4236,7 @@ qeth_arp_set_no_entries(struct qeth_card *card, int no_entries) tmp = rc; PRINT_WARN("Could not set number of ARP entries on %s: " "%s (0x%x/%d)\n", - card->info.if_name, qeth_arp_get_error_cause(&rc), + QETH_CARD_IFNAME(card), qeth_arp_get_error_cause(&rc), tmp, tmp); } return rc; @@ -4226,12 +4404,12 @@ qeth_arp_query(struct qeth_card *card, char *udata) * funcs flags); since all zeros is no valueable information, * we say EOPNOTSUPP for all ARP functions */ - if (card->info.guestlan) - return -EOPNOTSUPP; + /*if (card->info.guestlan) + return -EOPNOTSUPP; */ if (!qeth_is_supported(card,/*IPA_QUERY_ARP_ADDR_INFO*/ IPA_ARP_PROCESSING)) { PRINT_WARN("ARP processing not supported " - "on %s!\n", card->info.if_name); + "on %s!\n", QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } /* get size of userspace buffer and mask_bits -> 6 bytes */ @@ -4252,7 +4430,7 @@ qeth_arp_query(struct qeth_card *card, char *udata) tmp = rc; PRINT_WARN("Error while querying ARP cache on %s: %s " "(0x%x/%d)\n", - card->info.if_name, qeth_arp_get_error_cause(&rc), + QETH_CARD_IFNAME(card), qeth_arp_get_error_cause(&rc), tmp, tmp); copy_to_user(udata, qinfo.udata, 4); } else { @@ -4366,9 +4544,11 @@ qeth_snmp_command(struct qeth_card *card, char *udata) if (card->info.guestlan) return -EOPNOTSUPP; - if (!qeth_adp_supported(card,IPA_SETADP_SET_SNMP_CONTROL)) { + + if ((!qeth_adp_supported(card,IPA_SETADP_SET_SNMP_CONTROL)) && + (!card->options.layer2) ) { PRINT_WARN("SNMP Query MIBS not supported " - "on %s!\n", card->info.if_name); + "on %s!\n", QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } /* skip 4 bytes (data_len struct member) to get req_len */ @@ -4400,7 +4580,7 @@ qeth_snmp_command(struct qeth_card *card, char *udata) qeth_snmp_command_cb, (void *)&qinfo); if (rc) PRINT_WARN("SNMP command failed on %s: (0x%x)\n", - card->info.if_name, rc); + QETH_CARD_IFNAME(card), rc); else copy_to_user(udata, qinfo.udata, qinfo.udata_len); @@ -4440,7 +4620,7 @@ qeth_arp_add_entry(struct qeth_card *card, struct qeth_arp_cache_entry *entry) return -EOPNOTSUPP; if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) { PRINT_WARN("ARP processing not supported " - "on %s!\n", card->info.if_name); + "on %s!\n", QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } @@ -4457,7 +4637,7 @@ qeth_arp_add_entry(struct qeth_card *card, struct qeth_arp_cache_entry *entry) qeth_ipaddr4_to_string((u8 *)entry->ipaddr, buf); PRINT_WARN("Could not add ARP entry for address %s on %s: " "%s (0x%x/%d)\n", - buf, card->info.if_name, + buf, QETH_CARD_IFNAME(card), qeth_arp_get_error_cause(&rc), tmp, tmp); } return rc; @@ -4483,7 +4663,7 @@ qeth_arp_remove_entry(struct qeth_card *card, struct qeth_arp_cache_entry *entry return -EOPNOTSUPP; if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) { PRINT_WARN("ARP processing not supported " - "on %s!\n", card->info.if_name); + "on %s!\n", QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } memcpy(buf, entry, 12); @@ -4500,7 +4680,7 @@ qeth_arp_remove_entry(struct qeth_card *card, struct qeth_arp_cache_entry *entry qeth_ipaddr4_to_string((u8 *)entry->ipaddr, buf); PRINT_WARN("Could not delete ARP entry for address %s on %s: " "%s (0x%x/%d)\n", - buf, card->info.if_name, + buf, QETH_CARD_IFNAME(card), qeth_arp_get_error_cause(&rc), tmp, tmp); } return rc; @@ -4524,7 +4704,7 @@ qeth_arp_flush_cache(struct qeth_card *card) return -EOPNOTSUPP; if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) { PRINT_WARN("ARP processing not supported " - "on %s!\n", card->info.if_name); + "on %s!\n", QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } rc = qeth_send_simple_setassparms(card, IPA_ARP_PROCESSING, @@ -4532,7 +4712,7 @@ qeth_arp_flush_cache(struct qeth_card *card) if (rc){ tmp = rc; PRINT_WARN("Could not flush ARP cache on %s: %s (0x%x/%d)\n", - card->info.if_name, qeth_arp_get_error_cause(&rc), + QETH_CARD_IFNAME(card), qeth_arp_get_error_cause(&rc), tmp, tmp); } return rc; @@ -4555,21 +4735,24 @@ qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) switch (cmd){ case SIOC_QETH_ARP_SET_NO_ENTRIES: - if (!capable(CAP_NET_ADMIN)){ + if ( !capable(CAP_NET_ADMIN) || + (card->options.layer2) ) { rc = -EPERM; break; } rc = qeth_arp_set_no_entries(card, rq->ifr_ifru.ifru_ivalue); break; case SIOC_QETH_ARP_QUERY_INFO: - if (!capable(CAP_NET_ADMIN)){ + if ( !capable(CAP_NET_ADMIN) || + (card->options.layer2) ) { rc = -EPERM; break; } rc = qeth_arp_query(card, rq->ifr_ifru.ifru_data); break; case SIOC_QETH_ARP_ADD_ENTRY: - if (!capable(CAP_NET_ADMIN)){ + if ( !capable(CAP_NET_ADMIN) || + (card->options.layer2) ) { rc = -EPERM; break; } @@ -4580,7 +4763,8 @@ qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) rc = qeth_arp_add_entry(card, &arp_entry); break; case SIOC_QETH_ARP_REMOVE_ENTRY: - if (!capable(CAP_NET_ADMIN)){ + if ( !capable(CAP_NET_ADMIN) || + (card->options.layer2) ) { rc = -EPERM; break; } @@ -4591,7 +4775,8 @@ qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) rc = qeth_arp_remove_entry(card, &arp_entry); break; case SIOC_QETH_ARP_FLUSH_CACHE: - if (!capable(CAP_NET_ADMIN)){ + if ( !capable(CAP_NET_ADMIN) || + (card->options.layer2) ) { rc = -EPERM; break; } @@ -4741,7 +4926,7 @@ qeth_free_vlan_addresses4(struct qeth_card *card, unsigned short vid) in_dev = __in_dev_get(card->vlangrp->vlan_devices[vid]); if (!in_dev) goto out; - for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next){ + for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { addr = qeth_get_addr_buffer(QETH_PROT_IPV4); if (addr){ addr->u.a4.addr = ifa->ifa_address; @@ -4782,13 +4967,70 @@ qeth_free_vlan_addresses6(struct qeth_card *card, unsigned short vid) in6_dev_put(in6_dev); } +static void +qeth_layer2_send_setdelvlan(struct qeth_card *card, __u16 i, + enum qeth_ipa_cmds ipacmd) +{ + int rc; + struct qeth_ipa_cmd *cmd; + struct qeth_cmd_buffer *iob; + + QETH_DBF_TEXT_(trace, 4, "L2sdv%x",ipacmd); + iob = qeth_get_ipacmd_buffer(card, ipacmd, QETH_PROT_IPV4); + cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd->data.setdelvlan.vlan_id = i; + + rc = qeth_send_ipa_cmd(card, iob, NULL, NULL); + if (rc) { + PRINT_ERR("Error in processing VLAN %i on %s: 0x%x. " + "Continuing\n",i, QETH_CARD_IFNAME(card), rc); + QETH_DBF_TEXT_(trace, 2, "L2VL%4x", ipacmd); + QETH_DBF_TEXT_(trace, 2, "L2%s", CARD_BUS_ID(card)); + QETH_DBF_TEXT_(trace, 2, "err%d", rc); + } +} + +static void +qeth_layer2_process_vlans(struct qeth_card *card, int clear) +{ + unsigned short i; + + QETH_DBF_TEXT(trace, 3, "L2prcvln"); + + if (!card->vlangrp) + return; + for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { + if (card->vlangrp->vlan_devices[i] == NULL) + continue; + if (clear) + qeth_layer2_send_setdelvlan(card, i, IPA_CMD_DELVLAN); + else + qeth_layer2_send_setdelvlan(card, i, IPA_CMD_SETVLAN); + } +} + +/*add_vid is layer 2 used only ....*/ +static void +qeth_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) +{ + struct qeth_card *card; + + QETH_DBF_TEXT_(trace, 4, "aid:%d", vid); + + card = (struct qeth_card *) dev->priv; + if (!card->options.layer2) + return; + qeth_layer2_send_setdelvlan(card, vid, IPA_CMD_SETVLAN); +} + +/*... kill_vid used for both modes*/ static void qeth_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) { struct qeth_card *card; unsigned long flags; - QETH_DBF_TEXT(trace,4,"vlkilvid"); + QETH_DBF_TEXT_(trace, 4, "kid:%d", vid); card = (struct qeth_card *) dev->priv; /* free all skbs for the vlan device */ @@ -4800,38 +5042,35 @@ qeth_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) if (card->vlangrp) card->vlangrp->vlan_devices[vid] = NULL; spin_unlock_irqrestore(&card->vlanlock, flags); - if ( (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0) || - (qeth_set_thread_start_bit(card, QETH_SET_MC_THREAD) == 0) ) - schedule_work(&card->kernel_thread_starter); + if (card->options.layer2) + qeth_layer2_send_setdelvlan(card, vid, IPA_CMD_DELVLAN); + qeth_set_multicast_list(card->dev); } #endif -static int -qeth_neigh_setup(struct net_device *dev, struct neigh_parms *np) +/** + * set multicast address on card + */ +static void +qeth_set_multicast_list(struct net_device *dev) { - return 0; -} + struct qeth_card *card = (struct qeth_card *) dev->priv; + QETH_DBF_TEXT(trace,3,"setmulti"); + qeth_delete_mc_addresses(card); + qeth_add_multicast_ipv4(card); #ifdef CONFIG_QETH_IPV6 -int -qeth_ipv6_generate_eui64(u8 * eui, struct net_device *dev) -{ - switch (dev->type) { - case ARPHRD_ETHER: - case ARPHRD_FDDI: - case ARPHRD_IEEE802_TR: - if (dev->addr_len != ETH_ALEN) - return -1; - memcpy(eui, dev->dev_addr, 3); - memcpy(eui + 5, dev->dev_addr + 3, 3); - eui[3] = (dev->dev_id >> 8) & 0xff; - eui[4] = dev->dev_id & 0xff; - return 0; - } - return -1; + qeth_add_multicast_ipv6(card); +#endif + if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0) + schedule_work(&card->kernel_thread_starter); +} +static int +qeth_neigh_setup(struct net_device *dev, struct neigh_parms *np) +{ + return 0; } -#endif static void qeth_get_mac_for_ipm(__u32 ipm, char *mac, struct net_device *dev) @@ -4861,24 +5100,19 @@ qeth_get_addr_buffer(enum qeth_prot_versions prot) static void qeth_delete_mc_addresses(struct qeth_card *card) { - struct qeth_ipaddr *ipm, *iptodo; + struct qeth_ipaddr *iptodo; unsigned long flags; QETH_DBF_TEXT(trace,4,"delmc"); - spin_lock_irqsave(&card->ip_lock, flags); - list_for_each_entry(ipm, &card->ip_list, entry){ - if (!ipm->is_multicast) - continue; - iptodo = qeth_get_addr_buffer(ipm->proto); - if (!iptodo) { - QETH_DBF_TEXT(trace, 2, "dmcnomem"); - continue; - } - memcpy(iptodo, ipm, sizeof(struct qeth_ipaddr)); - iptodo->users = iptodo->users * -1; - if (!__qeth_insert_ip_todo(card, iptodo, 0)) - kfree(iptodo); + iptodo = qeth_get_addr_buffer(QETH_PROT_IPV4); + if (!iptodo) { + QETH_DBF_TEXT(trace, 2, "dmcnomem"); + return; } + iptodo->type = QETH_IP_TYPE_DEL_ALL_MC; + spin_lock_irqsave(&card->ip_lock, flags); + if (!__qeth_insert_ip_todo(card, iptodo, 0)) + kfree(iptodo); spin_unlock_irqrestore(&card->ip_lock, flags); } @@ -4912,8 +5146,9 @@ qeth_add_vlan_mc(struct qeth_card *card) int i; QETH_DBF_TEXT(trace,4,"addmcvl"); - if (!qeth_is_supported(card,IPA_FULL_VLAN) || - (card->vlangrp == NULL)) + if ( ((card->options.layer2 == 0) && + (!qeth_is_supported(card,IPA_FULL_VLAN))) || + (card->vlangrp == NULL) ) return ; vg = card->vlangrp; @@ -4980,8 +5215,9 @@ qeth_add_vlan_mc6(struct qeth_card *card) int i; QETH_DBF_TEXT(trace,4,"admc6vl"); - if (!qeth_is_supported(card,IPA_FULL_VLAN) || - (card->vlangrp == NULL)) + if ( ((card->options.layer2 == 0) && + (!qeth_is_supported(card,IPA_FULL_VLAN))) || + (card->vlangrp == NULL)) return ; vg = card->vlangrp; @@ -5020,19 +5256,182 @@ qeth_add_multicast_ipv6(struct qeth_card *card) } #endif /* CONFIG_QETH_IPV6 */ -/** - * set multicast address on card - */ -static void -qeth_set_multicast_list(struct net_device *dev) +static int +qeth_layer2_send_setdelmac(struct qeth_card *card, __u8 *mac, + enum qeth_ipa_cmds ipacmd, + int (*reply_cb) (struct qeth_card *, + struct qeth_reply*, + unsigned long)) +{ + struct qeth_ipa_cmd *cmd; + struct qeth_cmd_buffer *iob; + + QETH_DBF_TEXT(trace, 2, "L2sdmac"); + iob = qeth_get_ipacmd_buffer(card, ipacmd, QETH_PROT_IPV4); + cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd->data.setdelmac.mac_length = OSA_ADDR_LEN; + memcpy(&cmd->data.setdelmac.mac, mac, OSA_ADDR_LEN); + return qeth_send_ipa_cmd(card, iob, reply_cb, NULL); +} + +static int +qeth_layer2_send_setgroupmac_cb(struct qeth_card *card, + struct qeth_reply *reply, + unsigned long data) { + struct qeth_ipa_cmd *cmd; + __u8 *mac; + + QETH_DBF_TEXT(trace, 2, "L2Sgmacb"); + cmd = (struct qeth_ipa_cmd *) data; + mac = &cmd->data.setdelmac.mac[0]; + /* MAC already registered, needed in couple/uncouple case */ + if (cmd->hdr.return_code == 0x2005) { + PRINT_WARN("Group MAC %02x:%02x:%02x:%02x:%02x:%02x " \ + "already existing on %s \n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + QETH_CARD_IFNAME(card)); + cmd->hdr.return_code = 0; + } + if (cmd->hdr.return_code) + PRINT_ERR("Could not set group MAC " \ + "%02x:%02x:%02x:%02x:%02x:%02x on %s: %x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + QETH_CARD_IFNAME(card),cmd->hdr.return_code); + return 0; +} + +static int +qeth_layer2_send_setgroupmac(struct qeth_card *card, __u8 *mac) +{ + QETH_DBF_TEXT(trace, 2, "L2Sgmac"); + return qeth_layer2_send_setdelmac(card, mac, IPA_CMD_SETGMAC, + qeth_layer2_send_setgroupmac_cb); +} + +static int +qeth_layer2_send_delgroupmac_cb(struct qeth_card *card, + struct qeth_reply *reply, + unsigned long data) +{ + struct qeth_ipa_cmd *cmd; + __u8 *mac; + + QETH_DBF_TEXT(trace, 2, "L2Dgmacb"); + cmd = (struct qeth_ipa_cmd *) data; + mac = &cmd->data.setdelmac.mac[0]; + if (cmd->hdr.return_code) + PRINT_ERR("Could not delete group MAC " \ + "%02x:%02x:%02x:%02x:%02x:%02x on %s: %x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + QETH_CARD_IFNAME(card), cmd->hdr.return_code); + return 0; +} + +static int +qeth_layer2_send_delgroupmac(struct qeth_card *card, __u8 *mac) +{ + QETH_DBF_TEXT(trace, 2, "L2Dgmac"); + return qeth_layer2_send_setdelmac(card, mac, IPA_CMD_DELGMAC, + qeth_layer2_send_delgroupmac_cb); +} + +static int +qeth_layer2_send_setmac_cb(struct qeth_card *card, + struct qeth_reply *reply, + unsigned long data) +{ + struct qeth_ipa_cmd *cmd; + + QETH_DBF_TEXT(trace, 2, "L2Smaccb"); + cmd = (struct qeth_ipa_cmd *) data; + if (cmd->hdr.return_code) { + QETH_DBF_TEXT_(trace, 2, "L2er%x", cmd->hdr.return_code); + PRINT_WARN("Error in registering MAC address on " \ + "device %s: x%x\n", CARD_BUS_ID(card), + cmd->hdr.return_code); + card->info.layer2_mac_registered = 0; + cmd->hdr.return_code = -EIO; + } else { + card->info.layer2_mac_registered = 1; + memcpy(card->dev->dev_addr,cmd->data.setdelmac.mac, + OSA_ADDR_LEN); + PRINT_INFO("MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " + "successfully registered on device %s\n", + card->dev->dev_addr[0], card->dev->dev_addr[1], + card->dev->dev_addr[2], card->dev->dev_addr[3], + card->dev->dev_addr[4], card->dev->dev_addr[5], + card->dev->name); + } + return 0; +} + +static int +qeth_layer2_send_setmac(struct qeth_card *card, __u8 *mac) +{ + QETH_DBF_TEXT(trace, 2, "L2Setmac"); + return qeth_layer2_send_setdelmac(card, mac, IPA_CMD_SETVMAC, + qeth_layer2_send_setmac_cb); +} + +static int +qeth_layer2_send_delmac_cb(struct qeth_card *card, + struct qeth_reply *reply, + unsigned long data) +{ + struct qeth_ipa_cmd *cmd; + + QETH_DBF_TEXT(trace, 2, "L2Dmaccb"); + cmd = (struct qeth_ipa_cmd *) data; + if (cmd->hdr.return_code) { + PRINT_WARN("Error in deregistering MAC address on " \ + "device %s: x%x\n", CARD_BUS_ID(card), + cmd->hdr.return_code); + QETH_DBF_TEXT_(trace, 2, "err%d", cmd->hdr.return_code); + cmd->hdr.return_code = -EIO; + return 0; + } + card->info.layer2_mac_registered = 0; + + return 0; +} +static int +qeth_layer2_send_delmac(struct qeth_card *card, __u8 *mac) +{ + QETH_DBF_TEXT(trace, 2, "L2Delmac"); + if (!card->info.layer2_mac_registered) + return 0; + return qeth_layer2_send_setdelmac(card, mac, IPA_CMD_DELVMAC, + qeth_layer2_send_delmac_cb); +} + +static int +qeth_layer2_set_mac_address(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; struct qeth_card *card; + int rc = 0; - QETH_DBF_TEXT(trace,3,"setmulti"); + QETH_DBF_TEXT(trace, 3, "setmac"); + + if (qeth_verify_dev(dev) != QETH_REAL_CARD) { + QETH_DBF_TEXT(trace, 3, "setmcINV"); + return -EOPNOTSUPP; + } card = (struct qeth_card *) dev->priv; - if (qeth_set_thread_start_bit(card, QETH_SET_MC_THREAD) == 0) - schedule_work(&card->kernel_thread_starter); + if (!card->options.layer2) { + PRINT_WARN("Setting MAC address on %s is not supported" + "in Layer 3 mode.\n", dev->name); + QETH_DBF_TEXT(trace, 3, "setmcLY3"); + return -EOPNOTSUPP; + } + QETH_DBF_TEXT_(trace, 3, "%s", CARD_BUS_ID(card)); + QETH_DBF_HEX(trace, 3, addr->sa_data, OSA_ADDR_LEN); + rc = qeth_layer2_send_delmac(card, &card->dev->dev_addr[0]); + if (!rc) + rc = qeth_layer2_send_setmac(card, addr->sa_data); + return rc; } static void @@ -5045,7 +5444,10 @@ qeth_fill_ipacmd_header(struct qeth_card *card, struct qeth_ipa_cmd *cmd, cmd->hdr.seqno = card->seqno.ipa; cmd->hdr.adapter_type = qeth_get_ipa_adp_type(card->info.link_type); cmd->hdr.rel_adapter_no = (__u8) card->info.portno; - cmd->hdr.prim_version_no = 1; + if (card->options.layer2) + cmd->hdr.prim_version_no = 2; + else + cmd->hdr.prim_version_no = 1; cmd->hdr.param_count = 1; cmd->hdr.prot_version = prot; cmd->hdr.ipa_supported = 0; @@ -5136,7 +5538,30 @@ qeth_send_setdelip(struct qeth_card *card, struct qeth_ipaddr *addr, } static int -qeth_register_addr_entry(struct qeth_card *card, struct qeth_ipaddr *addr) +qeth_layer2_register_addr_entry(struct qeth_card *card, + struct qeth_ipaddr *addr) +{ + if (!addr->is_multicast) + return 0; + QETH_DBF_TEXT(trace, 2, "setgmac"); + QETH_DBF_HEX(trace,3,&addr->mac[0],OSA_ADDR_LEN); + return qeth_layer2_send_setgroupmac(card, &addr->mac[0]); +} + +static int +qeth_layer2_deregister_addr_entry(struct qeth_card *card, + struct qeth_ipaddr *addr) +{ + if (!addr->is_multicast) + return 0; + QETH_DBF_TEXT(trace, 2, "delgmac"); + QETH_DBF_HEX(trace,3,&addr->mac[0],OSA_ADDR_LEN); + return qeth_layer2_send_delgroupmac(card, &addr->mac[0]); +} + +static int +qeth_layer3_register_addr_entry(struct qeth_card *card, + struct qeth_ipaddr *addr) { //char buf[50]; int rc; @@ -5175,7 +5600,8 @@ qeth_register_addr_entry(struct qeth_card *card, struct qeth_ipaddr *addr) } static int -qeth_deregister_addr_entry(struct qeth_card *card, struct qeth_ipaddr *addr) +qeth_layer3_deregister_addr_entry(struct qeth_card *card, + struct qeth_ipaddr *addr) { //char buf[50]; int rc; @@ -5208,6 +5634,24 @@ qeth_deregister_addr_entry(struct qeth_card *card, struct qeth_ipaddr *addr) return rc; } +static int +qeth_register_addr_entry(struct qeth_card *card, struct qeth_ipaddr *addr) +{ + if (card->options.layer2) + return qeth_layer2_register_addr_entry(card, addr); + + return qeth_layer3_register_addr_entry(card, addr); +} + +static int +qeth_deregister_addr_entry(struct qeth_card *card, struct qeth_ipaddr *addr) +{ + if (card->options.layer2) + return qeth_layer2_deregister_addr_entry(card, addr); + + return qeth_layer3_deregister_addr_entry(card, addr); +} + static int qeth_netdev_init(struct net_device *dev) { @@ -5230,30 +5674,30 @@ qeth_netdev_init(struct net_device *dev) #ifdef CONFIG_QETH_VLAN dev->vlan_rx_register = qeth_vlan_rx_register; dev->vlan_rx_kill_vid = qeth_vlan_rx_kill_vid; + dev->vlan_rx_add_vid = qeth_vlan_rx_add_vid; #endif - if (qeth_get_netdev_flags(card->info.type) & IFF_NOARP) { + dev->hard_header = card->orig_hard_header; + if (qeth_get_netdev_flags(card) & IFF_NOARP) { dev->rebuild_header = NULL; dev->hard_header = NULL; + if (card->options.fake_ll) + dev->hard_header = qeth_fake_header; dev->header_cache_update = NULL; dev->hard_header_cache = NULL; } #ifdef CONFIG_QETH_IPV6 /*IPv6 address autoconfiguration stuff*/ - card->dev->dev_id = card->info.unique_id & 0xffff; if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD)) - card->dev->generate_eui64 = qeth_ipv6_generate_eui64; - - + card->dev->dev_id = card->info.unique_id & 0xffff; #endif dev->hard_header_parse = NULL; - dev->set_mac_address = NULL; - dev->flags |= qeth_get_netdev_flags(card->info.type); + dev->set_mac_address = qeth_layer2_set_mac_address; + dev->flags |= qeth_get_netdev_flags(card); if ((card->options.fake_broadcast) || (card->info.broadcast_capable)) dev->flags |= IFF_BROADCAST; - dev->hard_header_len = - qeth_get_hlen(card->info.link_type) + card->options.add_hhlen; + qeth_get_hlen(card->info.link_type) + card->options.add_hhlen; dev->addr_len = OSA_ADDR_LEN; dev->mtu = card->info.initial_mtu; @@ -5345,22 +5789,26 @@ retry: QETH_DBF_TEXT_(setup, 2, "5err%d", rc); goto out; } + /*network device will be recovered*/ + if (card->dev) { + card->dev->hard_header = card->orig_hard_header; + return 0; + } /* at first set_online allocate netdev */ + card->dev = qeth_get_netdevice(card->info.type, + card->info.link_type); if (!card->dev){ - card->dev = qeth_get_netdevice(card->info.type, - card->info.link_type); - if (!card->dev){ - qeth_qdio_clear_card(card, card->info.type == - QETH_CARD_TYPE_OSAE); - rc = -ENODEV; - QETH_DBF_TEXT_(setup, 2, "6err%d", rc); - goto out; - } - card->dev->priv = card; - card->dev->type = qeth_get_arphdr_type(card->info.type, - card->info.link_type); - card->dev->init = qeth_netdev_init; + qeth_qdio_clear_card(card, card->info.type == + QETH_CARD_TYPE_OSAE); + rc = -ENODEV; + QETH_DBF_TEXT_(setup, 2, "6err%d", rc); + goto out; } + card->dev->priv = card; + card->orig_hard_header = card->dev->hard_header; + card->dev->type = qeth_get_arphdr_type(card->info.type, + card->info.link_type); + card->dev->init = qeth_netdev_init; return 0; out: PRINT_ERR("Initialization in hardsetup failed! rc=%d\n", rc); @@ -5560,6 +6008,31 @@ qeth_setadapter_parms(struct qeth_card *card) return rc; } +static int +qeth_layer2_initialize(struct qeth_card *card) +{ + int rc = 0; + + + QETH_DBF_TEXT(setup, 2, "doL2init"); + QETH_DBF_TEXT_(setup, 2, "doL2%s", CARD_BUS_ID(card)); + + rc = qeth_setadpparms_change_macaddr(card); + if (rc) { + PRINT_WARN("couldn't get MAC address on " + "device %s: x%x\n", + CARD_BUS_ID(card), rc); + QETH_DBF_TEXT_(setup, 2,"1err%d",rc); + return rc; + } + QETH_DBF_HEX(setup,2, card->dev->dev_addr, OSA_ADDR_LEN); + + rc = qeth_layer2_send_setmac(card, &card->dev->dev_addr[0]); + if (rc) + QETH_DBF_TEXT_(setup, 2,"2err%d",rc); + return 0; +} + static int qeth_send_startstoplan(struct qeth_card *card, enum qeth_ipa_cmds ipacmd, @@ -5629,6 +6102,10 @@ qeth_query_ipassists(struct qeth_card *card, enum qeth_prot_versions prot) struct qeth_cmd_buffer *iob; QETH_DBF_TEXT_(setup, 2, "qipassi%i", prot); + if (card->options.layer2) { + QETH_DBF_TEXT(setup, 2, "noprmly2"); + return -EPERM; + } iob = qeth_get_ipacmd_buffer(card,IPA_CMD_QIPASSIST,prot); rc = qeth_send_ipa_cmd(card, iob, qeth_query_ipassists_cb, NULL); @@ -5724,7 +6201,7 @@ qeth_start_ipa_arp_processing(struct qeth_card *card) if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) { PRINT_WARN("ARP processing not supported " - "on %s!\n", card->info.if_name); + "on %s!\n", QETH_CARD_IFNAME(card)); return 0; } rc = qeth_send_simple_setassparms(card,IPA_ARP_PROCESSING, @@ -5732,7 +6209,7 @@ qeth_start_ipa_arp_processing(struct qeth_card *card) if (rc) { PRINT_WARN("Could not start ARP processing " "assist on %s: 0x%x\n", - card->info.if_name, rc); + QETH_CARD_IFNAME(card), rc); } return rc; } @@ -5746,7 +6223,7 @@ qeth_start_ipa_ip_fragmentation(struct qeth_card *card) if (!qeth_is_supported(card, IPA_IP_FRAGMENTATION)) { PRINT_INFO("Hardware IP fragmentation not supported on %s\n", - card->info.if_name); + QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } @@ -5755,7 +6232,7 @@ qeth_start_ipa_ip_fragmentation(struct qeth_card *card) if (rc) { PRINT_WARN("Could not start Hardware IP fragmentation " "assist on %s: 0x%x\n", - card->info.if_name, rc); + QETH_CARD_IFNAME(card), rc); } else PRINT_INFO("Hardware IP fragmentation enabled \n"); return rc; @@ -5773,7 +6250,7 @@ qeth_start_ipa_source_mac(struct qeth_card *card) if (!qeth_is_supported(card, IPA_SOURCE_MAC)) { PRINT_INFO("Inbound source address not " - "supported on %s\n", card->info.if_name); + "supported on %s\n", QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } @@ -5782,7 +6259,7 @@ qeth_start_ipa_source_mac(struct qeth_card *card) if (rc) PRINT_WARN("Could not start inbound source " "assist on %s: 0x%x\n", - card->info.if_name, rc); + QETH_CARD_IFNAME(card), rc); return rc; } @@ -5795,7 +6272,7 @@ qeth_start_ipa_vlan(struct qeth_card *card) #ifdef CONFIG_QETH_VLAN if (!qeth_is_supported(card, IPA_FULL_VLAN)) { - PRINT_WARN("VLAN not supported on %s\n", card->info.if_name); + PRINT_WARN("VLAN not supported on %s\n", QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } @@ -5804,10 +6281,13 @@ qeth_start_ipa_vlan(struct qeth_card *card) if (rc) { PRINT_WARN("Could not start vlan " "assist on %s: 0x%x\n", - card->info.if_name, rc); + QETH_CARD_IFNAME(card), rc); } else { PRINT_INFO("VLAN enabled \n"); - card->dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + card->dev->features |= + NETIF_F_HW_VLAN_FILTER | + NETIF_F_HW_VLAN_TX | + NETIF_F_HW_VLAN_RX; } #endif /* QETH_VLAN */ return rc; @@ -5822,7 +6302,7 @@ qeth_start_ipa_multicast(struct qeth_card *card) if (!qeth_is_supported(card, IPA_MULTICASTING)) { PRINT_WARN("Multicast not supported on %s\n", - card->info.if_name); + QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } @@ -5831,7 +6311,7 @@ qeth_start_ipa_multicast(struct qeth_card *card) if (rc) { PRINT_WARN("Could not start multicast " "assist on %s: rc=%i\n", - card->info.if_name, rc); + QETH_CARD_IFNAME(card), rc); } else { PRINT_INFO("Multicast enabled\n"); card->dev->flags |= IFF_MULTICAST; @@ -5851,14 +6331,14 @@ qeth_softsetup_ipv6(struct qeth_card *card) rc = qeth_send_startlan(card, QETH_PROT_IPV6); if (rc) { PRINT_ERR("IPv6 startlan failed on %s\n", - card->info.if_name); + QETH_CARD_IFNAME(card)); return rc; } netif_wake_queue(card->dev); rc = qeth_query_ipassists(card,QETH_PROT_IPV6); if (rc) { PRINT_ERR("IPv6 query ipassist failed on %s\n", - card->info.if_name); + QETH_CARD_IFNAME(card)); return rc; } rc = qeth_send_simple_setassparms(card, IPA_IPV6, @@ -5866,7 +6346,7 @@ qeth_softsetup_ipv6(struct qeth_card *card) if (rc) { PRINT_WARN("IPv6 start assist (version 4) failed " "on %s: 0x%x\n", - card->info.if_name, rc); + QETH_CARD_IFNAME(card), rc); return rc; } rc = qeth_send_simple_setassparms_ipv6(card, IPA_IPV6, @@ -5874,7 +6354,7 @@ qeth_softsetup_ipv6(struct qeth_card *card) if (rc) { PRINT_WARN("IPV6 start assist (version 6) failed " "on %s: 0x%x\n", - card->info.if_name, rc); + QETH_CARD_IFNAME(card), rc); return rc; } rc = qeth_send_simple_setassparms_ipv6(card, IPA_PASSTHRU, @@ -5882,7 +6362,7 @@ qeth_softsetup_ipv6(struct qeth_card *card) if (rc) { PRINT_WARN("Could not enable passthrough " "on %s: 0x%x\n", - card->info.if_name, rc); + QETH_CARD_IFNAME(card), rc); return rc; } PRINT_INFO("IPV6 enabled \n"); @@ -5900,7 +6380,7 @@ qeth_start_ipa_ipv6(struct qeth_card *card) if (!qeth_is_supported(card, IPA_IPV6)) { PRINT_WARN("IPv6 not supported on %s\n", - card->info.if_name); + QETH_CARD_IFNAME(card)); return 0; } rc = qeth_softsetup_ipv6(card); @@ -5917,7 +6397,7 @@ qeth_start_ipa_broadcast(struct qeth_card *card) card->info.broadcast_capable = 0; if (!qeth_is_supported(card, IPA_FILTERING)) { PRINT_WARN("Broadcast not supported on %s\n", - card->info.if_name); + QETH_CARD_IFNAME(card)); rc = -EOPNOTSUPP; goto out; } @@ -5926,7 +6406,7 @@ qeth_start_ipa_broadcast(struct qeth_card *card) if (rc) { PRINT_WARN("Could not enable broadcasting filtering " "on %s: 0x%x\n", - card->info.if_name, rc); + QETH_CARD_IFNAME(card), rc); goto out; } @@ -5934,7 +6414,7 @@ qeth_start_ipa_broadcast(struct qeth_card *card) IPA_CMD_ASS_CONFIGURE, 1); if (rc) { PRINT_WARN("Could not set up broadcast filtering on %s: 0x%x\n", - card->info.if_name, rc); + QETH_CARD_IFNAME(card), rc); goto out; } card->info.broadcast_capable = QETH_BROADCAST_WITH_ECHO; @@ -5943,7 +6423,7 @@ qeth_start_ipa_broadcast(struct qeth_card *card) IPA_CMD_ASS_ENABLE, 1); if (rc) { PRINT_WARN("Could not set up broadcast echo filtering on " - "%s: 0x%x\n", card->info.if_name, rc); + "%s: 0x%x\n", QETH_CARD_IFNAME(card), rc); goto out; } card->info.broadcast_capable = QETH_BROADCAST_WITHOUT_ECHO; @@ -5965,7 +6445,7 @@ qeth_send_checksum_command(struct qeth_card *card) if (rc) { PRINT_WARN("Starting Inbound HW Checksumming failed on %s: " "0x%x,\ncontinuing using Inbound SW Checksumming\n", - card->info.if_name, rc); + QETH_CARD_IFNAME(card), rc); return rc; } rc = qeth_send_simple_setassparms(card, IPA_INBOUND_CHECKSUM, @@ -5974,7 +6454,7 @@ qeth_send_checksum_command(struct qeth_card *card) if (rc) { PRINT_WARN("Enabling Inbound HW Checksumming failed on %s: " "0x%x,\ncontinuing using Inbound SW Checksumming\n", - card->info.if_name, rc); + QETH_CARD_IFNAME(card), rc); return rc; } return 0; @@ -5989,19 +6469,19 @@ qeth_start_ipa_checksum(struct qeth_card *card) if (card->options.checksum_type == NO_CHECKSUMMING) { PRINT_WARN("Using no checksumming on %s.\n", - card->info.if_name); + QETH_CARD_IFNAME(card)); return 0; } if (card->options.checksum_type == SW_CHECKSUMMING) { PRINT_WARN("Using SW checksumming on %s.\n", - card->info.if_name); + QETH_CARD_IFNAME(card)); return 0; } if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) { PRINT_WARN("Inbound HW Checksumming not " "supported on %s,\ncontinuing " "using Inbound SW Checksumming\n", - card->info.if_name); + QETH_CARD_IFNAME(card)); card->options.checksum_type = SW_CHECKSUMMING; return 0; } @@ -6123,7 +6603,7 @@ qeth_setrouting_v4(struct qeth_card *card) card->options.route4.type = NO_ROUTER; PRINT_WARN("Error (0x%04x) while setting routing type on %s. " "Type set to 'no router'.\n", - rc, card->info.if_name); + rc, QETH_CARD_IFNAME(card)); } return rc; } @@ -6150,7 +6630,7 @@ qeth_setrouting_v6(struct qeth_card *card) card->options.route6.type = NO_ROUTER; PRINT_WARN("Error (0x%04x) while setting routing type on %s. " "Type set to 'no router'.\n", - rc, card->info.if_name); + rc, QETH_CARD_IFNAME(card)); } #endif return rc; @@ -6177,6 +6657,22 @@ qeth_softsetup_card(struct qeth_card *card) return rc; } else card->lan_online = 1; + if (card->options.layer2) { + card->dev->features |= + NETIF_F_HW_VLAN_FILTER | + NETIF_F_HW_VLAN_TX | + NETIF_F_HW_VLAN_RX; + card->dev->flags|=IFF_MULTICAST|IFF_BROADCAST; + card->info.broadcast_capable=1; + if ((rc = qeth_layer2_initialize(card))) { + QETH_DBF_TEXT_(setup, 2, "L2err%d", rc); + return rc; + } +#ifdef CONFIG_QETH_VLAN + qeth_layer2_process_vlans(card, 0); +#endif + goto out; + } if ((rc = qeth_setadapter_parms(card))) QETH_DBF_TEXT_(setup, 2, "2err%d", rc); if ((rc = qeth_start_ipassists(card))) @@ -6185,6 +6681,7 @@ qeth_softsetup_card(struct qeth_card *card) QETH_DBF_TEXT_(setup, 2, "4err%d", rc); if ((rc = qeth_setrouting_v6(card))) QETH_DBF_TEXT_(setup, 2, "5err%d", rc); +out: netif_stop_queue(card->dev); return 0; } @@ -6255,7 +6752,7 @@ qeth_clear_ip_list(struct qeth_card *card, int clean, int recover) QETH_DBF_TEXT(trace,4,"clearip"); spin_lock_irqsave(&card->ip_lock, flags); /* clear todo list */ - list_for_each_entry_safe(addr, tmp, &card->ip_tbd_list, entry){ + list_for_each_entry_safe(addr, tmp, card->ip_tbd_list, entry){ list_del(&addr->entry); kfree(addr); } @@ -6273,7 +6770,7 @@ qeth_clear_ip_list(struct qeth_card *card, int clean, int recover) kfree(addr); continue; } - list_add_tail(&addr->entry, &card->ip_tbd_list); + list_add_tail(&addr->entry, card->ip_tbd_list); } spin_unlock_irqrestore(&card->ip_lock, flags); } @@ -6314,7 +6811,6 @@ qeth_wait_for_threads(struct qeth_card *card, unsigned long threads) static int qeth_stop_card(struct qeth_card *card) { - int recover_flag = 0; int rc = 0; QETH_DBF_TEXT(setup ,2,"stopcard"); @@ -6326,22 +6822,30 @@ qeth_stop_card(struct qeth_card *card) if (card->read.state == CH_STATE_UP && card->write.state == CH_STATE_UP && (card->state == CARD_STATE_UP)) { - recover_flag = 1; rtnl_lock(); dev_close(card->dev); rtnl_unlock(); - if (!card->use_hard_stop) + if (!card->use_hard_stop) { + __u8 *mac = &card->dev->dev_addr[0]; + rc = qeth_layer2_send_delmac(card, mac); + QETH_DBF_TEXT_(setup, 2, "Lerr%d", rc); if ((rc = qeth_send_stoplan(card))) QETH_DBF_TEXT_(setup, 2, "1err%d", rc); + } card->state = CARD_STATE_SOFTSETUP; } if (card->state == CARD_STATE_SOFTSETUP) { - qeth_clear_ip_list(card, !card->use_hard_stop, recover_flag); +#ifdef CONFIG_QETH_VLAN + if (card->options.layer2) + qeth_layer2_process_vlans(card, 1); +#endif + qeth_clear_ip_list(card, !card->use_hard_stop, 1); qeth_clear_ipacmd_list(card); card->state = CARD_STATE_HARDSETUP; } if (card->state == CARD_STATE_HARDSETUP) { - if (!card->use_hard_stop) + if ((!card->use_hard_stop) && + (!card->options.layer2)) if ((rc = qeth_put_unique_id(card))) QETH_DBF_TEXT_(setup, 2, "2err%d", rc); qeth_qdio_clear_card(card, 0); @@ -6481,18 +6985,14 @@ qeth_print_status_message(struct qeth_card *card) static int qeth_register_netdev(struct qeth_card *card) { - int rc; - QETH_DBF_TEXT(setup, 3, "regnetd"); - if (card->dev->reg_state != NETREG_UNINITIALIZED) + if (card->dev->reg_state != NETREG_UNINITIALIZED) { + qeth_netdev_init(card->dev); return 0; + } /* sysfs magic */ SET_NETDEV_DEV(card->dev, &card->gdev->dev); - rc = register_netdev(card->dev); - if (!rc) - strcpy(card->info.if_name, card->dev->name); - - return rc; + return register_netdev(card->dev); } static void @@ -6503,10 +7003,61 @@ qeth_start_again(struct qeth_card *card) rtnl_lock(); dev_open(card->dev); rtnl_unlock(); - if (qeth_set_thread_start_bit(card, QETH_SET_MC_THREAD) == 0) - schedule_work(&card->kernel_thread_starter); + /* this also sets saved unicast addresses */ + qeth_set_multicast_list(card->dev); +} + + +/* Layer 2 specific stuff */ +#define IGNORE_PARAM_EQ(option,value,reset_value,msg) \ + if (card->options.option == value) { \ + PRINT_ERR("%s not supported with layer 2 " \ + "functionality, ignoring option on read" \ + "channel device %s .\n",msg,CARD_RDEV_ID(card)); \ + card->options.option = reset_value; \ + } +#define IGNORE_PARAM_NEQ(option,value,reset_value,msg) \ + if (card->options.option != value) { \ + PRINT_ERR("%s not supported with layer 2 " \ + "functionality, ignoring option on read" \ + "channel device %s .\n",msg,CARD_RDEV_ID(card)); \ + card->options.option = reset_value; \ + } + + +static void qeth_make_parameters_consistent(struct qeth_card *card) +{ + + if (card->options.layer2) { + if (card->info.type == QETH_CARD_TYPE_IQD) { + PRINT_ERR("Device %s does not support " \ + "layer 2 functionality. " \ + "Ignoring layer2 option.\n",CARD_BUS_ID(card)); + } + IGNORE_PARAM_NEQ(route4.type, NO_ROUTER, NO_ROUTER, + "Routing options are"); +#ifdef CONFIG_QETH_IPV6 + IGNORE_PARAM_NEQ(route6.type, NO_ROUTER, NO_ROUTER, + "Routing options are"); +#endif + IGNORE_PARAM_EQ(checksum_type, HW_CHECKSUMMING, + QETH_CHECKSUM_DEFAULT, + "Checksumming options are"); + IGNORE_PARAM_NEQ(broadcast_mode, QETH_TR_BROADCAST_ALLRINGS, + QETH_TR_BROADCAST_ALLRINGS, + "Broadcast mode options are"); + IGNORE_PARAM_NEQ(macaddr_mode, QETH_TR_MACADDR_NONCANONICAL, + QETH_TR_MACADDR_NONCANONICAL, + "Canonical MAC addr options are"); + IGNORE_PARAM_NEQ(fake_broadcast, 0, 0, + "Broadcast faking options are"); + IGNORE_PARAM_NEQ(add_hhlen, DEFAULT_ADD_HHLEN, + DEFAULT_ADD_HHLEN,"Option add_hhlen is"); + IGNORE_PARAM_NEQ(fake_ll, 0, 0,"Option fake_ll is"); + } } + static int qeth_set_online(struct ccwgroup_device *gdev) { @@ -6526,47 +7077,50 @@ qeth_set_online(struct ccwgroup_device *gdev) } recover_flag = card->state; - if (ccw_device_set_online(CARD_RDEV(card)) || - ccw_device_set_online(CARD_WDEV(card)) || - ccw_device_set_online(CARD_DDEV(card))){ + if ((rc = ccw_device_set_online(CARD_RDEV(card))) || + (rc = ccw_device_set_online(CARD_WDEV(card))) || + (rc = ccw_device_set_online(CARD_DDEV(card)))){ QETH_DBF_TEXT_(setup, 2, "1err%d", rc); return -EIO; } + if (card->options.layer2) + qeth_make_parameters_consistent(card); + if ((rc = qeth_hardsetup_card(card))){ QETH_DBF_TEXT_(setup, 2, "2err%d", rc); goto out_remove; } card->state = CARD_STATE_HARDSETUP; - if ((rc = qeth_query_ipassists(card,QETH_PROT_IPV4))){ - QETH_DBF_TEXT_(setup, 2, "3err%d", rc); - /*TODO: rc !=0*/ - } else + if (!(rc = qeth_query_ipassists(card,QETH_PROT_IPV4))) rc = qeth_get_unique_id(card); - if (rc) { - QETH_DBF_TEXT_(setup, 2, "4err%d", rc); + if (rc && card->options.layer2 == 0) { + QETH_DBF_TEXT_(setup, 2, "3err%d", rc); goto out_remove; } qeth_print_status_message(card); if ((rc = qeth_register_netdev(card))){ - QETH_DBF_TEXT_(setup, 2, "5err%d", rc); + QETH_DBF_TEXT_(setup, 2, "4err%d", rc); goto out_remove; } if ((rc = qeth_softsetup_card(card))){ - QETH_DBF_TEXT_(setup, 2, "6err%d", rc); + QETH_DBF_TEXT_(setup, 2, "5err%d", rc); goto out_remove; } card->state = CARD_STATE_SOFTSETUP; if ((rc = qeth_init_qdio_queues(card))){ - QETH_DBF_TEXT_(setup, 2, "7err%d", rc); + QETH_DBF_TEXT_(setup, 2, "6err%d", rc); goto out_remove; } /*maybe it was set offline without ifconfig down * we can also use this state for recovery purposes*/ - qeth_set_allowed_threads(card, 0xffffffff, 0); + if (card->options.layer2) + qeth_set_allowed_threads(card, QETH_RECOVER_THREAD, 0); + else + qeth_set_allowed_threads(card, 0xffffffff, 0); if (recover_flag == CARD_STATE_RECOVER) qeth_start_again(card); qeth_notify_processes(); @@ -6714,10 +7268,14 @@ qeth_arp_constructor(struct neighbour *neigh) struct net_device *dev = neigh->dev; struct in_device *in_dev; struct neigh_parms *parms; + struct qeth_card *card; - if (!qeth_verify_dev(dev)) { - return qeth_old_arp_constructor(neigh); - } + card = qeth_get_card_from_dev(dev); + if (card == NULL) + goto out; + if((card->options.layer2) || + (card->dev->hard_header == qeth_fake_header)) + goto out; rcu_read_lock(); in_dev = rcu_dereference(__in_dev_get(dev)); @@ -6736,6 +7294,8 @@ qeth_arp_constructor(struct neighbour *neigh) neigh->ops = arp_direct_ops; neigh->output = neigh->ops->queue_xmit; return 0; +out: + return qeth_old_arp_constructor(neigh); } #endif /*CONFIG_QETH_IPV6*/ @@ -6888,7 +7448,7 @@ qeth_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto, return -ENOMEM; spin_lock_irqsave(&card->ip_lock, flags); if (__qeth_address_exists_in_list(&card->ip_list, ipaddr, 0) || - __qeth_address_exists_in_list(&card->ip_tbd_list, ipaddr, 0)) + __qeth_address_exists_in_list(card->ip_tbd_list, ipaddr, 0)) rc = -EEXIST; spin_unlock_irqrestore(&card->ip_lock, flags); if (rc){ @@ -6961,7 +7521,7 @@ qeth_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto, return -ENOMEM; spin_lock_irqsave(&card->ip_lock, flags); if (__qeth_address_exists_in_list(&card->ip_list, ipaddr, 0) || - __qeth_address_exists_in_list(&card->ip_tbd_list, ipaddr, 0)) + __qeth_address_exists_in_list(card->ip_tbd_list, ipaddr, 0)) rc = -EEXIST; spin_unlock_irqrestore(&card->ip_lock, flags); if (rc){ @@ -7019,6 +7579,8 @@ qeth_ip_event(struct notifier_block *this, card = qeth_get_card_from_dev(dev); if (!card) return NOTIFY_DONE; + if (card->options.layer2) + return NOTIFY_DONE; addr = qeth_get_addr_buffer(QETH_PROT_IPV4); if (addr != NULL) {