diff options
author | Joonas Lahtinen <joonas.lahtinen@linux.intel.com> | 2018-03-01 12:14:24 +0300 |
---|---|---|
committer | Joonas Lahtinen <joonas.lahtinen@linux.intel.com> | 2018-03-01 12:14:24 +0300 |
commit | bba73071b6f71be0a101658d7c13866e30b264a6 (patch) | |
tree | 2a0ea1fc5fd975f1c2e9e50de5bb3cb2cb3cb5f7 /drivers/s390 | |
parent | c71b53cc66c5053ff3524a6132f8fc8199d618c3 (diff) | |
parent | f073d78eeb8efd85718e611c15f9a78647751dea (diff) | |
download | linux-bba73071b6f71be0a101658d7c13866e30b264a6.tar.xz |
Merge drm-next into drm-intel-next-queued (this time for real)
To pull in the HDCP changes, especially wait_for changes to drm/i915
that Chris wants to build on top of.
Signed-off-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Diffstat (limited to 'drivers/s390')
29 files changed, 428 insertions, 602 deletions
diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig index bc27d716aa6b..1444333210c7 100644 --- a/drivers/s390/block/Kconfig +++ b/drivers/s390/block/Kconfig @@ -16,6 +16,7 @@ config BLK_DEV_XPRAM config DCSSBLK def_tristate m select DAX + select FS_DAX_LIMITED prompt "DCSSBLK support" depends on S390 && BLOCK help diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index d4e8dff673cc..a7c15f0085e2 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1393,10 +1393,6 @@ int dasd_term_IO(struct dasd_ccw_req *cqr) DBF_DEV_EVENT(DBF_ERR, device, "%s", "device gone, retry"); break; - case -EIO: - DBF_DEV_EVENT(DBF_ERR, device, "%s", - "I/O error, retry"); - break; case -EINVAL: /* * device not valid so no I/O could be running @@ -1412,10 +1408,6 @@ int dasd_term_IO(struct dasd_ccw_req *cqr) /* fake rc to success */ rc = 0; break; - case -EBUSY: - DBF_DEV_EVENT(DBF_ERR, device, "%s", - "device busy, retry later"); - break; default: /* internal error 10 - unknown rc*/ snprintf(errorstring, ERRORLENGTH, "10 %d", rc); @@ -1489,10 +1481,6 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) DBF_DEV_EVENT(DBF_WARNING, device, "%s", "start_IO: device busy, retry later"); break; - case -ETIMEDOUT: - DBF_DEV_EVENT(DBF_WARNING, device, "%s", - "start_IO: request timeout, retry later"); - break; case -EACCES: /* -EACCES indicates that the request used only a subset of the * available paths and all these paths are gone. If the lpm of diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index a2edf2a7ace9..29397a9dba68 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -5231,7 +5231,7 @@ static int dasd_hosts_print(struct dasd_device *device, struct seq_file *m) struct dasd_ckd_path_group_entry *entry; struct dasd_ckd_host_information *info; char sysplex[9] = ""; - int rc, i, j; + int rc, i; access = kzalloc(sizeof(*access), GFP_NOIO); if (!access) { @@ -5251,10 +5251,7 @@ static int dasd_hosts_print(struct dasd_device *device, struct seq_file *m) entry = (struct dasd_ckd_path_group_entry *) (info->entry + i * info->entry_size); /* PGID */ - seq_puts(m, "pgid "); - for (j = 0; j < 11; j++) - seq_printf(m, "%02x", entry->pgid[j]); - seq_putc(m, '\n'); + seq_printf(m, "pgid %*phN\n", 11, entry->pgid); /* FLAGS */ seq_printf(m, "status_flags %02x\n", entry->status_flags); /* SYSPLEX NAME */ diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index a7917d473774..fb2c3599d95c 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -661,9 +661,9 @@ static ssize_t dasd_eer_read(struct file *filp, char __user *buf, return effective_count; } -static unsigned int dasd_eer_poll(struct file *filp, poll_table *ptable) +static __poll_t dasd_eer_poll(struct file *filp, poll_table *ptable) { - unsigned int mask; + __poll_t mask; unsigned long flags; struct eerbuffer *eerb; @@ -671,7 +671,7 @@ static unsigned int dasd_eer_poll(struct file *filp, poll_table *ptable) poll_wait(filp, &dasd_eer_read_wait_queue, ptable); spin_lock_irqsave(&bufferlock, flags); if (eerb->head != eerb->tail) - mask = POLLIN | POLLRDNORM ; + mask = EPOLLIN | EPOLLRDNORM ; else mask = 0; spin_unlock_irqrestore(&bufferlock, flags); diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 6aaefb780436..9cae08b36b80 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -916,7 +916,8 @@ __dcssblk_direct_access(struct dcssblk_dev_info *dev_info, pgoff_t pgoff, dev_sz = dev_info->end - dev_info->start + 1; *kaddr = (void *) dev_info->start + offset; - *pfn = __pfn_to_pfn_t(PFN_DOWN(dev_info->start + offset), PFN_DEV); + *pfn = __pfn_to_pfn_t(PFN_DOWN(dev_info->start + offset), + PFN_DEV|PFN_SPECIAL); return (dev_sz - offset) / PAGE_SIZE; } diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index 614b44e70a28..a2b33a22c82a 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -19,6 +19,8 @@ endif CFLAGS_sclp_early_core.o += -D__NO_FORTIFY +CFLAGS_REMOVE_sclp_early_core.o += $(CC_FLAGS_EXPOLINE) + obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o \ sclp_early.o sclp_early_core.o diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index bf4ab4efed73..7bc616b253f1 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -429,15 +429,15 @@ out_copy: return count; } -static unsigned int mon_poll(struct file *filp, struct poll_table_struct *p) +static __poll_t mon_poll(struct file *filp, struct poll_table_struct *p) { struct mon_private *monpriv = filp->private_data; poll_wait(filp, &mon_read_wait_queue, p); if (unlikely(atomic_read(&monpriv->iucv_severed))) - return POLLERR; + return EPOLLERR; if (atomic_read(&monpriv->read_ready)) - return POLLIN | POLLRDNORM; + return EPOLLIN | EPOLLRDNORM; return 0; } diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index d06bc5674e5f..6b1891539c84 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -49,7 +49,7 @@ struct read_info_sccb { u8 _pad_112[116 - 112]; /* 112-115 */ u8 fac116; /* 116 */ u8 fac117; /* 117 */ - u8 _pad_118; /* 118 */ + u8 fac118; /* 118 */ u8 fac119; /* 119 */ u16 hcpua; /* 120-121 */ u8 _pad_122[124 - 122]; /* 122-123 */ @@ -100,6 +100,7 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb) sclp.has_esca = !!(sccb->fac116 & 0x08); sclp.has_pfmfi = !!(sccb->fac117 & 0x40); sclp.has_ibs = !!(sccb->fac117 & 0x20); + sclp.has_gisaf = !!(sccb->fac118 & 0x08); sclp.has_hvs = !!(sccb->fac119 & 0x80); sclp.has_kss = !!(sccb->fac98 & 0x01); if (sccb->fac85 & 0x02) diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c index edeb2597b0b8..17b0c67f3e8d 100644 --- a/drivers/s390/char/sclp_early_core.c +++ b/drivers/s390/char/sclp_early_core.c @@ -12,8 +12,8 @@ #include "sclp.h" #include "sclp_rw.h" -char sclp_early_sccb[PAGE_SIZE] __aligned(PAGE_SIZE) __section(data); -int sclp_init_state __section(data) = sclp_init_state_uninitialized; +char sclp_early_sccb[PAGE_SIZE] __aligned(PAGE_SIZE) __section(.data); +int sclp_init_state __section(.data) = sclp_init_state_uninitialized; void sclp_early_wait_irq(void) { diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 5c94a3aec4dd..f95b452b8bbc 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -412,7 +412,7 @@ static void chp_release(struct device *dev) /** * chp_update_desc - update channel-path description - * @chp - channel-path + * @chp: channel-path * * Update the channel-path description of the specified channel-path * including channel measurement related information. @@ -438,7 +438,7 @@ int chp_update_desc(struct channel_path *chp) /** * chp_new - register a new channel-path - * @chpid - channel-path ID + * @chpid: channel-path ID * * Create and register data structure representing new channel-path. Return * zero on success, non-zero otherwise. @@ -730,8 +730,8 @@ static void cfg_func(struct work_struct *work) /** * chp_cfg_schedule - schedule chpid configuration request - * @chpid - channel-path ID - * @configure - Non-zero for configure, zero for deconfigure + * @chpid: channel-path ID + * @configure: Non-zero for configure, zero for deconfigure * * Schedule a channel-path configuration/deconfiguration request. */ @@ -747,7 +747,7 @@ void chp_cfg_schedule(struct chp_id chpid, int configure) /** * chp_cfg_cancel_deconfigure - cancel chpid deconfiguration request - * @chpid - channel-path ID + * @chpid: channel-path ID * * Cancel an active channel-path deconfiguration request if it has not yet * been performed. diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 987bf9a8c9f7..6886b3d34cf8 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -1059,7 +1059,7 @@ EXPORT_SYMBOL_GPL(cio_tm_start_key); /** * cio_tm_intrg - perform interrogate function - * @sch - subchannel on which to perform the interrogate function + * @sch: subchannel on which to perform the interrogate function * * If the specified subchannel is running in transport-mode, perform the * interrogate function. Return zero on success, non-zero otherwie. diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 5e495c62cfa7..8af4948dae80 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -1118,9 +1118,10 @@ int ccw_set_cmf(struct ccw_device *cdev, int enable) * enable_cmf() - switch on the channel measurement for a specific device * @cdev: The ccw device to be enabled * - * Returns %0 for success or a negative error value. - * Note: If this is called on a device for which channel measurement is already - * enabled a reset of the measurement data is triggered. + * Enable channel measurements for @cdev. If this is called on a device + * for which channel measurement is already enabled a reset of the + * measurement data is triggered. + * Returns: %0 for success or a negative error value. * Context: * non-atomic */ @@ -1160,7 +1161,7 @@ out_unlock: * __disable_cmf() - switch off the channel measurement for a specific device * @cdev: The ccw device to be disabled * - * Returns %0 for success or a negative error value. + * Returns: %0 for success or a negative error value. * * Context: * non-atomic, device_lock() held. @@ -1184,7 +1185,7 @@ int __disable_cmf(struct ccw_device *cdev) * disable_cmf() - switch off the channel measurement for a specific device * @cdev: The ccw device to be disabled * - * Returns %0 for success or a negative error value. + * Returns: %0 for success or a negative error value. * * Context: * non-atomic @@ -1205,7 +1206,7 @@ int disable_cmf(struct ccw_device *cdev) * @cdev: the channel to be read * @index: the index of the value to be read * - * Returns the value read or %0 if the value cannot be read. + * Returns: The value read or %0 if the value cannot be read. * * Context: * any @@ -1220,7 +1221,7 @@ u64 cmf_read(struct ccw_device *cdev, int index) * @cdev: the channel to be read * @data: a pointer to a data block that will be filled * - * Returns %0 on success, a negative error value otherwise. + * Returns: %0 on success, a negative error value otherwise. * * Context: * any diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 0f11dce6e224..9263a0fb3858 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -268,7 +268,7 @@ static ssize_t type_show(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%01x\n", sch->st); } -static DEVICE_ATTR(type, 0444, type_show, NULL); +static DEVICE_ATTR_RO(type); static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -278,7 +278,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, return sprintf(buf, "css:t%01X\n", sch->st); } -static DEVICE_ATTR(modalias, 0444, modalias_show, NULL); +static DEVICE_ATTR_RO(modalias); static struct attribute *subch_attrs[] = { &dev_attr_type.attr, @@ -315,7 +315,7 @@ static ssize_t chpids_show(struct device *dev, ret += sprintf(buf + ret, "\n"); return ret; } -static DEVICE_ATTR(chpids, 0444, chpids_show, NULL); +static DEVICE_ATTR_RO(chpids); static ssize_t pimpampom_show(struct device *dev, struct device_attribute *attr, @@ -327,7 +327,7 @@ static ssize_t pimpampom_show(struct device *dev, return sprintf(buf, "%02x %02x %02x\n", pmcw->pim, pmcw->pam, pmcw->pom); } -static DEVICE_ATTR(pimpampom, 0444, pimpampom_show, NULL); +static DEVICE_ATTR_RO(pimpampom); static struct attribute *io_subchannel_type_attrs[] = { &dev_attr_chpids.attr, diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 75a245f38e2e..f50ea035aa9b 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -597,13 +597,13 @@ static ssize_t vpm_show(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%02x\n", sch->vpm); } -static DEVICE_ATTR(devtype, 0444, devtype_show, NULL); -static DEVICE_ATTR(cutype, 0444, cutype_show, NULL); -static DEVICE_ATTR(modalias, 0444, modalias_show, NULL); -static DEVICE_ATTR(online, 0644, online_show, online_store); +static DEVICE_ATTR_RO(devtype); +static DEVICE_ATTR_RO(cutype); +static DEVICE_ATTR_RO(modalias); +static DEVICE_ATTR_RW(online); static DEVICE_ATTR(availability, 0444, available_show, NULL); static DEVICE_ATTR(logging, 0200, NULL, initiate_logging); -static DEVICE_ATTR(vpm, 0444, vpm_show, NULL); +static DEVICE_ATTR_RO(vpm); static struct attribute *io_subchannel_attrs[] = { &dev_attr_logging.attr, diff --git a/drivers/s390/cio/itcw.c b/drivers/s390/cio/itcw.c index deaf59f93326..19e46363348c 100644 --- a/drivers/s390/cio/itcw.c +++ b/drivers/s390/cio/itcw.c @@ -15,7 +15,7 @@ #include <asm/fcx.h> #include <asm/itcw.h> -/** +/* * struct itcw - incremental tcw helper data type * * This structure serves as a handle for the incremental construction of a diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 95b0efe28afb..d5b02de02a3a 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -72,6 +72,7 @@ static inline int do_siga_input(unsigned long schid, unsigned int mask, * @mask: which output queues to process * @bb: busy bit indicator, set only if SIGA-w/wt could not access a buffer * @fc: function code to perform + * @aob: asynchronous operation block * * Returns condition code. * Note: For IQDC unicast queues only the highest priority queue is processed. @@ -1761,9 +1762,6 @@ EXPORT_SYMBOL(qdio_stop_irq); * @response: Response code will be stored at this address * @cb: Callback function will be executed for each element * of the address list - * @priv: Pointer passed from the caller to qdio_pnso_brinfo() - * @type: Type of the address entry passed to the callback - * @entry: Entry containg the address of the specified type * @priv: Pointer to pass to the callback function. * * Performs "Store-network-bridging-information list" operation and calls diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c index d9a2fffd034b..2c7550797ec2 100644 --- a/drivers/s390/cio/vfio_ccw_cp.c +++ b/drivers/s390/cio/vfio_ccw_cp.c @@ -835,7 +835,7 @@ void cp_update_scsw(struct channel_program *cp, union scsw *scsw) /** * cp_iova_pinned() - check if an iova is pinned for a ccw chain. - * @cmd: ccwchain command on which to perform the operation + * @cp: channel_program on which to perform the operation * @iova: the iova to check * * If the @iova is currently pinned for the ccw chain, return true; diff --git a/drivers/s390/crypto/ap_card.c b/drivers/s390/crypto/ap_card.c index 97a8cf578116..2c726df210f6 100644 --- a/drivers/s390/crypto/ap_card.c +++ b/drivers/s390/crypto/ap_card.c @@ -57,7 +57,7 @@ static ssize_t ap_functions_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "0x%08X\n", ac->functions); } -static DEVICE_ATTR(ap_functions, 0444, ap_functions_show, NULL); +static DEVICE_ATTR_RO(ap_functions); static ssize_t ap_req_count_show(struct device *dev, struct device_attribute *attr, diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig index a782a207ad31..c7e484f70654 100644 --- a/drivers/s390/net/Kconfig +++ b/drivers/s390/net/Kconfig @@ -91,9 +91,6 @@ config QETH_L3 To compile as a module choose M. The module name is qeth_l3. If unsure, choose Y. -config QETH_IPV6 - def_bool y if (QETH_L3 = IPV6) || (QETH_L3 && IPV6 = 'y') - config CCWGROUP tristate default (LCS || CTCM || QETH) diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 92ae84a927fc..0ee8f33efb54 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -756,18 +756,14 @@ lcs_get_lancmd(struct lcs_card *card, int count) static void lcs_get_reply(struct lcs_reply *reply) { - WARN_ON(atomic_read(&reply->refcnt) <= 0); - atomic_inc(&reply->refcnt); + refcount_inc(&reply->refcnt); } static void lcs_put_reply(struct lcs_reply *reply) { - WARN_ON(atomic_read(&reply->refcnt) <= 0); - if (atomic_dec_and_test(&reply->refcnt)) { + if (refcount_dec_and_test(&reply->refcnt)) kfree(reply); - } - } static struct lcs_reply * @@ -780,7 +776,7 @@ lcs_alloc_reply(struct lcs_cmd *cmd) reply = kzalloc(sizeof(struct lcs_reply), GFP_ATOMIC); if (!reply) return NULL; - atomic_set(&reply->refcnt,1); + refcount_set(&reply->refcnt, 1); reply->sequence_no = cmd->sequence_no; reply->received = 0; reply->rc = 0; diff --git a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h index fbc8b90b1f85..bd52caa3b11b 100644 --- a/drivers/s390/net/lcs.h +++ b/drivers/s390/net/lcs.h @@ -5,6 +5,7 @@ #include <linux/netdevice.h> #include <linux/skbuff.h> #include <linux/workqueue.h> +#include <linux/refcount.h> #include <asm/ccwdev.h> #define LCS_DBF_TEXT(level, name, text) \ @@ -271,7 +272,7 @@ struct lcs_buffer { struct lcs_reply { struct list_head list; __u16 sequence_no; - atomic_t refcnt; + refcount_t refcnt; /* Callback for completion notification. */ void (*callback)(struct lcs_card *, struct lcs_cmd *); wait_queue_head_t wait_q; diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index badf42acbf95..959c65cf75d9 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -21,6 +21,7 @@ #include <linux/ethtool.h> #include <linux/hashtable.h> #include <linux/ip.h> +#include <linux/refcount.h> #include <net/ipv6.h> #include <net/if_inet6.h> @@ -296,8 +297,23 @@ struct qeth_hdr_layer3 { __u8 ext_flags; __u16 vlan_id; __u16 frame_offset; - __u8 dest_addr[16]; -} __attribute__ ((packed)); + union { + /* TX: */ + u8 ipv6_addr[16]; + struct ipv4 { + u8 res[12]; + u32 addr; + } ipv4; + /* RX: */ + struct rx { + u8 res1[2]; + u8 src_mac[6]; + u8 res2[4]; + u16 vlan_id; + u8 res3[2]; + } rx; + } next_hop; +}; struct qeth_hdr_layer2 { __u8 id; @@ -504,12 +520,6 @@ struct qeth_qdio_info { int default_out_queue; }; -#define QETH_ETH_MAC_V4 0x0100 /* like v4 */ -#define QETH_ETH_MAC_V6 0x3333 /* like v6 */ -/* tr mc mac is longer, but that will be enough to detect mc frames */ -#define QETH_TR_MAC_NC 0xc000 /* non-canonical */ -#define QETH_TR_MAC_C 0x0300 /* canonical */ - /** * buffer stuff for read channel */ @@ -581,6 +591,11 @@ struct qeth_cmd_buffer { void (*callback) (struct qeth_channel *, struct qeth_cmd_buffer *); }; +static inline struct qeth_ipa_cmd *__ipa_cmd(struct qeth_cmd_buffer *iob) +{ + return (struct qeth_ipa_cmd *)(iob->data + IPA_PDU_HEADER_SIZE); +} + /** * definition of a qeth channel, used for read and write */ @@ -632,7 +647,7 @@ struct qeth_reply { int rc; void *param; struct qeth_card *card; - atomic_t refcnt; + refcount_t refcnt; }; struct qeth_card_blkt { @@ -836,7 +851,7 @@ struct qeth_trap_id { */ static inline int qeth_get_elements_for_range(addr_t start, addr_t end) { - return PFN_UP(end - 1) - PFN_DOWN(start); + return PFN_UP(end) - PFN_DOWN(start); } static inline int qeth_get_micros(void) @@ -846,14 +861,16 @@ static inline int qeth_get_micros(void) static inline int qeth_get_ip_version(struct sk_buff *skb) { - __be16 *p = &((struct ethhdr *)skb->data)->h_proto; + struct vlan_ethhdr *veth = vlan_eth_hdr(skb); + __be16 prot = veth->h_vlan_proto; + + if (prot == htons(ETH_P_8021Q)) + prot = veth->h_vlan_encapsulated_proto; - if (be16_to_cpu(*p) == ETH_P_8021Q) - p += 2; - switch (be16_to_cpu(*p)) { - case ETH_P_IPV6: + switch (prot) { + case htons(ETH_P_IPV6): return 6; - case ETH_P_IP: + case htons(ETH_P_IP): return 4; default: return 0; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 3614df68830f..ca72f3311004 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -36,6 +36,7 @@ #include <asm/diag.h> #include <asm/cio.h> #include <asm/ccwdev.h> +#include <asm/cpcmd.h> #include "qeth_core.h" @@ -564,7 +565,7 @@ static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card) reply = kzalloc(sizeof(struct qeth_reply), GFP_ATOMIC); if (reply) { - atomic_set(&reply->refcnt, 1); + refcount_set(&reply->refcnt, 1); atomic_set(&reply->received, 0); reply->card = card; } @@ -573,14 +574,12 @@ static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card) static void qeth_get_reply(struct qeth_reply *reply) { - WARN_ON(atomic_read(&reply->refcnt) <= 0); - atomic_inc(&reply->refcnt); + refcount_inc(&reply->refcnt); } static void qeth_put_reply(struct qeth_reply *reply) { - WARN_ON(atomic_read(&reply->refcnt) <= 0); - if (atomic_dec_and_test(&reply->refcnt)) + if (refcount_dec_and_test(&reply->refcnt)) kfree(reply); } @@ -1717,23 +1716,87 @@ static void qeth_configure_unitaddr(struct qeth_card *card, char *prcd) (prcd[0x11] == _ascebc['M'])); } +static enum qeth_discipline_id qeth_vm_detect_layer(struct qeth_card *card) +{ + enum qeth_discipline_id disc = QETH_DISCIPLINE_UNDETERMINED; + struct diag26c_vnic_resp *response = NULL; + struct diag26c_vnic_req *request = NULL; + struct ccw_dev_id id; + char userid[80]; + int rc = 0; + + QETH_DBF_TEXT(SETUP, 2, "vmlayer"); + + cpcmd("QUERY USERID", userid, sizeof(userid), &rc); + if (rc) + goto out; + + request = kzalloc(sizeof(*request), GFP_KERNEL | GFP_DMA); + response = kzalloc(sizeof(*response), GFP_KERNEL | GFP_DMA); + if (!request || !response) { + rc = -ENOMEM; + goto out; + } + + ccw_device_get_id(CARD_RDEV(card), &id); + request->resp_buf_len = sizeof(*response); + request->resp_version = DIAG26C_VERSION6_VM65918; + request->req_format = DIAG26C_VNIC_INFO; + ASCEBC(userid, 8); + memcpy(&request->sys_name, userid, 8); + request->devno = id.devno; + + QETH_DBF_HEX(CTRL, 2, request, sizeof(*request)); + rc = diag26c(request, response, DIAG26C_PORT_VNIC); + QETH_DBF_HEX(CTRL, 2, request, sizeof(*request)); + if (rc) + goto out; + QETH_DBF_HEX(CTRL, 2, response, sizeof(*response)); + + if (request->resp_buf_len < sizeof(*response) || + response->version != request->resp_version) { + rc = -EIO; + goto out; + } + + if (response->protocol == VNIC_INFO_PROT_L2) + disc = QETH_DISCIPLINE_LAYER2; + else if (response->protocol == VNIC_INFO_PROT_L3) + disc = QETH_DISCIPLINE_LAYER3; + +out: + kfree(response); + kfree(request); + if (rc) + QETH_DBF_TEXT_(SETUP, 2, "err%x", rc); + return disc; +} + /* Determine whether the device requires a specific layer discipline */ static enum qeth_discipline_id qeth_enforce_discipline(struct qeth_card *card) { + enum qeth_discipline_id disc = QETH_DISCIPLINE_UNDETERMINED; + if (card->info.type == QETH_CARD_TYPE_OSM || - card->info.type == QETH_CARD_TYPE_OSN) { + card->info.type == QETH_CARD_TYPE_OSN) + disc = QETH_DISCIPLINE_LAYER2; + else if (card->info.guestlan) + disc = (card->info.type == QETH_CARD_TYPE_IQD) ? + QETH_DISCIPLINE_LAYER3 : + qeth_vm_detect_layer(card); + + switch (disc) { + case QETH_DISCIPLINE_LAYER2: QETH_DBF_TEXT(SETUP, 3, "force l2"); - return QETH_DISCIPLINE_LAYER2; - } - - /* virtual HiperSocket is L3 only: */ - if (card->info.guestlan && card->info.type == QETH_CARD_TYPE_IQD) { + break; + case QETH_DISCIPLINE_LAYER3: QETH_DBF_TEXT(SETUP, 3, "force l3"); - return QETH_DISCIPLINE_LAYER3; + break; + default: + QETH_DBF_TEXT(SETUP, 3, "force no"); } - QETH_DBF_TEXT(SETUP, 3, "force no"); - return QETH_DISCIPLINE_UNDETERMINED; + return disc; } static void qeth_configure_blkt_default(struct qeth_card *card, char *prcd) @@ -2057,7 +2120,7 @@ int qeth_send_control_data(struct qeth_card *card, int len, unsigned long flags; struct qeth_reply *reply = NULL; unsigned long timeout, event_timeout; - struct qeth_ipa_cmd *cmd; + struct qeth_ipa_cmd *cmd = NULL; QETH_CARD_TEXT(card, 2, "sendctl"); @@ -2083,10 +2146,13 @@ int qeth_send_control_data(struct qeth_card *card, int len, while (atomic_cmpxchg(&card->write.irq_pending, 0, 1)) ; qeth_prepare_control_data(card, len, iob); - if (IS_IPA(iob->data)) + if (IS_IPA(iob->data)) { + cmd = __ipa_cmd(iob); event_timeout = QETH_IPA_TIMEOUT; - else + } else { event_timeout = QETH_TIMEOUT; + } + timeout = jiffies + event_timeout; QETH_CARD_TEXT(card, 6, "noirqpnd"); @@ -2111,9 +2177,8 @@ int qeth_send_control_data(struct qeth_card *card, int len, /* we have only one long running ipassist, since we can ensure process context of this command we can sleep */ - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); - if ((cmd->hdr.command == IPA_CMD_SETIP) && - (cmd->hdr.prot_version == QETH_PROT_IPV4)) { + if (cmd && cmd->hdr.command == IPA_CMD_SETIP && + cmd->hdr.prot_version == QETH_PROT_IPV4) { if (!wait_event_timeout(reply->wait_q, atomic_read(&reply->received), event_timeout)) goto time_err; @@ -4218,9 +4283,8 @@ static int qeth_setadpparms_change_macaddr_cb(struct qeth_card *card, cmd = (struct qeth_ipa_cmd *) data; if (!card->options.layer2 || !(card->info.mac_bits & QETH_LAYER2_MAC_READ)) { - memcpy(card->dev->dev_addr, - &cmd->data.setadapterparms.data.change_addr.addr, - OSA_ADDR_LEN); + ether_addr_copy(card->dev->dev_addr, + cmd->data.setadapterparms.data.change_addr.addr); card->info.mac_bits |= QETH_LAYER2_MAC_READ; } qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd); @@ -4242,9 +4306,9 @@ int qeth_setadpparms_change_macaddr(struct qeth_card *card) return -ENOMEM; cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); cmd->data.setadapterparms.data.change_addr.cmd = CHANGE_ADDR_READ_MAC; - cmd->data.setadapterparms.data.change_addr.addr_size = OSA_ADDR_LEN; - memcpy(&cmd->data.setadapterparms.data.change_addr.addr, - card->dev->dev_addr, OSA_ADDR_LEN); + cmd->data.setadapterparms.data.change_addr.addr_size = ETH_ALEN; + ether_addr_copy(cmd->data.setadapterparms.data.change_addr.addr, + card->dev->dev_addr); rc = qeth_send_ipa_cmd(card, iob, qeth_setadpparms_change_macaddr_cb, NULL); return rc; @@ -4789,9 +4853,12 @@ int qeth_vm_request_mac(struct qeth_card *card) request->op_code = DIAG26C_GET_MAC; request->devno = id.devno; + QETH_DBF_HEX(CTRL, 2, request, sizeof(*request)); rc = diag26c(request, response, DIAG26C_MAC_SERVICES); + QETH_DBF_HEX(CTRL, 2, request, sizeof(*request)); if (rc) goto out; + QETH_DBF_HEX(CTRL, 2, response, sizeof(*response)); if (request->resp_buf_len < sizeof(*response) || response->version != request->resp_version) { diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index ff6877f7b6f8..619f897b4bb0 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -10,6 +10,7 @@ #define __QETH_CORE_MPC_H__ #include <asm/qeth.h> +#include <uapi/linux/if_ether.h> #define IPA_PDU_HEADER_SIZE 0x40 #define QETH_IPA_PDU_LEN_TOTAL(buffer) (buffer + 0x0e) @@ -25,7 +26,6 @@ extern unsigned char IPA_PDU_HEADER[]; #define QETH_SEQ_NO_LENGTH 4 #define QETH_MPC_TOKEN_LENGTH 4 #define QETH_MCL_LENGTH 4 -#define OSA_ADDR_LEN 6 #define QETH_TIMEOUT (10 * HZ) #define QETH_IPA_TIMEOUT (45 * HZ) @@ -416,12 +416,11 @@ struct qeth_query_cmds_supp { } __attribute__ ((packed)); struct qeth_change_addr { - __u32 cmd; - __u32 addr_size; - __u32 no_macs; - __u8 addr[OSA_ADDR_LEN]; -} __attribute__ ((packed)); - + u32 cmd; + u32 addr_size; + u32 no_macs; + u8 addr[ETH_ALEN]; +}; struct qeth_snmp_cmd { __u8 token[16]; diff --git a/drivers/s390/net/qeth_l2.h b/drivers/s390/net/qeth_l2.h index 09b1c4ef3dc9..f2130051ca11 100644 --- a/drivers/s390/net/qeth_l2.h +++ b/drivers/s390/net/qeth_l2.h @@ -22,8 +22,7 @@ int qeth_l2_vnicc_get_timeout(struct qeth_card *card, u32 *timeout); bool qeth_l2_vnicc_is_in_use(struct qeth_card *card); struct qeth_mac { - u8 mac_addr[OSA_ADDR_LEN]; - u8 is_uc:1; + u8 mac_addr[ETH_ALEN]; u8 disp_flag:2; struct hlist_node hnode; }; diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 5863ea170ff2..7f236440483f 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -109,8 +109,8 @@ static int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac, if (!iob) return -ENOMEM; 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); + cmd->data.setdelmac.mac_length = ETH_ALEN; + ether_addr_copy(cmd->data.setdelmac.mac, mac); return qeth_setdelmac_makerc(card, qeth_send_ipa_cmd(card, iob, NULL, NULL)); } @@ -123,7 +123,7 @@ static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac) rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC); if (rc == 0) { card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED; - memcpy(card->dev->dev_addr, mac, OSA_ADDR_LEN); + ether_addr_copy(card->dev->dev_addr, mac); dev_info(&card->gdev->dev, "MAC address %pM successfully registered on device %s\n", card->dev->dev_addr, card->dev->name); @@ -156,54 +156,37 @@ static int qeth_l2_send_delmac(struct qeth_card *card, __u8 *mac) return rc; } -static int qeth_l2_send_setgroupmac(struct qeth_card *card, __u8 *mac) +static int qeth_l2_write_mac(struct qeth_card *card, u8 *mac) { + enum qeth_ipa_cmds cmd = is_multicast_ether_addr_64bits(mac) ? + IPA_CMD_SETGMAC : IPA_CMD_SETVMAC; int rc; - QETH_CARD_TEXT(card, 2, "L2Sgmac"); - rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETGMAC); + QETH_CARD_TEXT(card, 2, "L2Wmac"); + rc = qeth_l2_send_setdelmac(card, mac, cmd); if (rc == -EEXIST) - QETH_DBF_MESSAGE(2, "Group MAC %pM already existing on %s\n", - mac, QETH_CARD_IFNAME(card)); + QETH_DBF_MESSAGE(2, "MAC %pM already registered on %s\n", + mac, QETH_CARD_IFNAME(card)); else if (rc) - QETH_DBF_MESSAGE(2, "Could not set group MAC %pM on %s: %d\n", - mac, QETH_CARD_IFNAME(card), rc); + QETH_DBF_MESSAGE(2, "Failed to register MAC %pM on %s: %d\n", + mac, QETH_CARD_IFNAME(card), rc); return rc; } -static int qeth_l2_send_delgroupmac(struct qeth_card *card, __u8 *mac) +static int qeth_l2_remove_mac(struct qeth_card *card, u8 *mac) { + enum qeth_ipa_cmds cmd = is_multicast_ether_addr_64bits(mac) ? + IPA_CMD_DELGMAC : IPA_CMD_DELVMAC; int rc; - QETH_CARD_TEXT(card, 2, "L2Dgmac"); - rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_DELGMAC); + QETH_CARD_TEXT(card, 2, "L2Rmac"); + rc = qeth_l2_send_setdelmac(card, mac, cmd); if (rc) - QETH_DBF_MESSAGE(2, - "Could not delete group MAC %pM on %s: %d\n", - mac, QETH_CARD_IFNAME(card), rc); + QETH_DBF_MESSAGE(2, "Failed to delete MAC %pM on %s: %d\n", + mac, QETH_CARD_IFNAME(card), rc); return rc; } -static int qeth_l2_write_mac(struct qeth_card *card, struct qeth_mac *mac) -{ - if (mac->is_uc) { - return qeth_l2_send_setdelmac(card, mac->mac_addr, - IPA_CMD_SETVMAC); - } else { - return qeth_l2_send_setgroupmac(card, mac->mac_addr); - } -} - -static int qeth_l2_remove_mac(struct qeth_card *card, struct qeth_mac *mac) -{ - if (mac->is_uc) { - return qeth_l2_send_setdelmac(card, mac->mac_addr, - IPA_CMD_DELVMAC); - } else { - return qeth_l2_send_delgroupmac(card, mac->mac_addr); - } -} - static void qeth_l2_del_all_macs(struct qeth_card *card) { struct qeth_mac *mac; @@ -549,7 +532,7 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p) QETH_CARD_TEXT(card, 3, "setmcTYP"); return -EOPNOTSUPP; } - QETH_CARD_HEX(card, 3, addr->sa_data, OSA_ADDR_LEN); + QETH_CARD_HEX(card, 3, addr->sa_data, ETH_ALEN); if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) { QETH_CARD_TEXT(card, 3, "setmcREC"); return -ERESTARTSYS; @@ -597,27 +580,23 @@ static void qeth_promisc_to_bridge(struct qeth_card *card) * only if there is not in the hash table storage already * */ -static void qeth_l2_add_mac(struct qeth_card *card, struct netdev_hw_addr *ha, - u8 is_uc) +static void qeth_l2_add_mac(struct qeth_card *card, struct netdev_hw_addr *ha) { u32 mac_hash = get_unaligned((u32 *)(&ha->addr[2])); struct qeth_mac *mac; hash_for_each_possible(card->mac_htable, mac, hnode, mac_hash) { - if (is_uc == mac->is_uc && - !memcmp(ha->addr, mac->mac_addr, OSA_ADDR_LEN)) { + if (ether_addr_equal_64bits(ha->addr, mac->mac_addr)) { mac->disp_flag = QETH_DISP_ADDR_DO_NOTHING; return; } } mac = kzalloc(sizeof(struct qeth_mac), GFP_ATOMIC); - if (!mac) return; - memcpy(mac->mac_addr, ha->addr, OSA_ADDR_LEN); - mac->is_uc = is_uc; + ether_addr_copy(mac->mac_addr, ha->addr); mac->disp_flag = QETH_DISP_ADDR_ADD; hash_add(card->mac_htable, &mac->hnode, mac_hash); @@ -643,26 +622,29 @@ static void qeth_l2_set_rx_mode(struct net_device *dev) spin_lock_bh(&card->mclock); netdev_for_each_mc_addr(ha, dev) - qeth_l2_add_mac(card, ha, 0); - + qeth_l2_add_mac(card, ha); netdev_for_each_uc_addr(ha, dev) - qeth_l2_add_mac(card, ha, 1); + qeth_l2_add_mac(card, ha); hash_for_each_safe(card->mac_htable, i, tmp, mac, hnode) { - if (mac->disp_flag == QETH_DISP_ADDR_DELETE) { - qeth_l2_remove_mac(card, mac); + switch (mac->disp_flag) { + case QETH_DISP_ADDR_DELETE: + qeth_l2_remove_mac(card, mac->mac_addr); hash_del(&mac->hnode); kfree(mac); - - } else if (mac->disp_flag == QETH_DISP_ADDR_ADD) { - rc = qeth_l2_write_mac(card, mac); + break; + case QETH_DISP_ADDR_ADD: + rc = qeth_l2_write_mac(card, mac->mac_addr); if (rc) { hash_del(&mac->hnode); kfree(mac); - } else - mac->disp_flag = QETH_DISP_ADDR_DELETE; - } else + break; + } + /* fall through */ + default: + /* for next call to set_rx_mode(): */ mac->disp_flag = QETH_DISP_ADDR_DELETE; + } } spin_unlock_bh(&card->mclock); diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h index e5833837b799..bdd45f4dcace 100644 --- a/drivers/s390/net/qeth_l3.h +++ b/drivers/s390/net/qeth_l3.h @@ -29,7 +29,7 @@ struct qeth_ipaddr { */ int ref_counter; enum qeth_prot_versions proto; - unsigned char mac[OSA_ADDR_LEN]; + unsigned char mac[ETH_ALEN]; union { struct { unsigned int addr; @@ -69,19 +69,20 @@ struct qeth_ipato_entry { extern const struct attribute_group *qeth_l3_attr_groups[]; void qeth_l3_ipaddr_to_string(enum qeth_prot_versions, const __u8 *, char *); -int qeth_l3_string_to_ipaddr(const char *, enum qeth_prot_versions, __u8 *); int qeth_l3_create_device_attributes(struct device *); void qeth_l3_remove_device_attributes(struct device *); int qeth_l3_setrouting_v4(struct qeth_card *); int qeth_l3_setrouting_v6(struct qeth_card *); int qeth_l3_add_ipato_entry(struct qeth_card *, struct qeth_ipato_entry *); -void qeth_l3_del_ipato_entry(struct qeth_card *, enum qeth_prot_versions, - u8 *, int); +int qeth_l3_del_ipato_entry(struct qeth_card *card, + enum qeth_prot_versions proto, u8 *addr, + int mask_bits); int qeth_l3_add_vipa(struct qeth_card *, enum qeth_prot_versions, const u8 *); -void qeth_l3_del_vipa(struct qeth_card *, enum qeth_prot_versions, const u8 *); +int qeth_l3_del_vipa(struct qeth_card *card, enum qeth_prot_versions proto, + const u8 *addr); int qeth_l3_add_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *); -void qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions, - const u8 *); +int qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions proto, + const u8 *addr); void qeth_l3_update_ipato(struct qeth_card *card); struct qeth_ipaddr *qeth_l3_get_addr_buffer(enum qeth_prot_versions); int qeth_l3_add_ip(struct qeth_card *, struct qeth_ipaddr *); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index ef0961e18686..b0c888e86cd4 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -18,15 +18,20 @@ #include <linux/kernel.h> #include <linux/etherdevice.h> #include <linux/ip.h> +#include <linux/in.h> #include <linux/ipv6.h> #include <linux/inetdevice.h> #include <linux/igmp.h> #include <linux/slab.h> +#include <linux/if_ether.h> #include <linux/if_vlan.h> +#include <linux/skbuff.h> #include <net/ip.h> #include <net/arp.h> #include <net/route.h> +#include <net/ipv6.h> +#include <net/ip6_route.h> #include <net/ip6_fib.h> #include <net/ip6_checksum.h> #include <net/iucv/af_iucv.h> @@ -37,99 +42,22 @@ static int qeth_l3_set_offline(struct ccwgroup_device *); static int qeth_l3_stop(struct net_device *); -static void qeth_l3_set_multicast_list(struct net_device *); +static void qeth_l3_set_rx_mode(struct net_device *dev); static int qeth_l3_register_addr_entry(struct qeth_card *, struct qeth_ipaddr *); static int qeth_l3_deregister_addr_entry(struct qeth_card *, struct qeth_ipaddr *); -static int qeth_l3_isxdigit(char *buf) -{ - while (*buf) { - if (!isxdigit(*buf++)) - return 0; - } - return 1; -} - static void qeth_l3_ipaddr4_to_string(const __u8 *addr, char *buf) { sprintf(buf, "%pI4", addr); } -static int qeth_l3_string_to_ipaddr4(const char *buf, __u8 *addr) -{ - int count = 0, rc = 0; - unsigned int in[4]; - char c; - - rc = sscanf(buf, "%u.%u.%u.%u%c", - &in[0], &in[1], &in[2], &in[3], &c); - if (rc != 4 && (rc != 5 || c != '\n')) - return -EINVAL; - for (count = 0; count < 4; count++) { - if (in[count] > 255) - return -EINVAL; - addr[count] = in[count]; - } - return 0; -} - static void qeth_l3_ipaddr6_to_string(const __u8 *addr, char *buf) { sprintf(buf, "%pI6", addr); } -static int qeth_l3_string_to_ipaddr6(const char *buf, __u8 *addr) -{ - const char *end, *end_tmp, *start; - __u16 *in; - char num[5]; - int num2, cnt, out, found, save_cnt; - unsigned short in_tmp[8] = {0, }; - - cnt = out = found = save_cnt = num2 = 0; - end = start = buf; - in = (__u16 *) addr; - memset(in, 0, 16); - while (*end) { - end = strchr(start, ':'); - if (end == NULL) { - end = buf + strlen(buf); - end_tmp = strchr(start, '\n'); - if (end_tmp != NULL) - end = end_tmp; - out = 1; - } - if ((end - start)) { - memset(num, 0, 5); - if ((end - start) > 4) - return -EINVAL; - memcpy(num, start, end - start); - if (!qeth_l3_isxdigit(num)) - return -EINVAL; - sscanf(start, "%x", &num2); - if (found) - in_tmp[save_cnt++] = num2; - else - in[cnt++] = num2; - if (out) - break; - } else { - if (found) - return -EINVAL; - found = 1; - } - start = ++end; - } - if (cnt + save_cnt > 8) - return -EINVAL; - cnt = 7; - while (save_cnt) - in[cnt--] = in_tmp[--save_cnt]; - return 0; -} - void qeth_l3_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr, char *buf) { @@ -139,17 +67,6 @@ void qeth_l3_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr, qeth_l3_ipaddr6_to_string(addr, buf); } -int qeth_l3_string_to_ipaddr(const char *buf, enum qeth_prot_versions proto, - __u8 *addr) -{ - if (proto == QETH_PROT_IPV4) - return qeth_l3_string_to_ipaddr4(buf, addr); - else if (proto == QETH_PROT_IPV6) - return qeth_l3_string_to_ipaddr6(buf, addr); - else - return -EINVAL; -} - static void qeth_l3_convert_addr_to_bits(u8 *addr, u8 *bits, int len) { int i, j; @@ -207,8 +124,8 @@ inline int qeth_l3_ipaddrs_is_equal(struct qeth_ipaddr *addr1, struct qeth_ipaddr *addr2) { return addr1->proto == addr2->proto && - !memcmp(&addr1->u, &addr2->u, sizeof(addr1->u)) && - !memcmp(&addr1->mac, &addr2->mac, sizeof(addr1->mac)); + !memcmp(&addr1->u, &addr2->u, sizeof(addr1->u)) && + ether_addr_equal_64bits(addr1->mac, addr2->mac); } static struct qeth_ipaddr * @@ -446,7 +363,7 @@ static int qeth_l3_send_setdelmc(struct qeth_card *card, if (!iob) return -ENOMEM; cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); - memcpy(&cmd->data.setdelipm.mac, addr->mac, OSA_ADDR_LEN); + ether_addr_copy(cmd->data.setdelipm.mac, addr->mac); if (addr->proto == QETH_PROT_IPV6) memcpy(cmd->data.setdelipm.ip6, &addr->u.a6.addr, sizeof(struct in6_addr)); @@ -582,7 +499,6 @@ int qeth_l3_setrouting_v6(struct qeth_card *card) int rc = 0; QETH_CARD_TEXT(card, 3, "setrtg6"); -#ifdef CONFIG_QETH_IPV6 if (!qeth_is_supported(card, IPA_IPV6)) return 0; @@ -599,7 +515,6 @@ int qeth_l3_setrouting_v6(struct qeth_card *card) " on %s. Type set to 'no router'.\n", rc, QETH_CARD_IFNAME(card)); } -#endif return rc; } @@ -673,10 +588,12 @@ int qeth_l3_add_ipato_entry(struct qeth_card *card, return rc; } -void qeth_l3_del_ipato_entry(struct qeth_card *card, - enum qeth_prot_versions proto, u8 *addr, int mask_bits) +int qeth_l3_del_ipato_entry(struct qeth_card *card, + enum qeth_prot_versions proto, u8 *addr, + int mask_bits) { struct qeth_ipato_entry *ipatoe, *tmp; + int rc = -ENOENT; QETH_CARD_TEXT(card, 2, "delipato"); @@ -691,10 +608,12 @@ void qeth_l3_del_ipato_entry(struct qeth_card *card, list_del(&ipatoe->entry); qeth_l3_update_ipato(card); kfree(ipatoe); + rc = 0; } } spin_unlock_bh(&card->ip_lock); + return rc; } /* @@ -704,7 +623,7 @@ int qeth_l3_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto, const u8 *addr) { struct qeth_ipaddr *ipaddr; - int rc = 0; + int rc; ipaddr = qeth_l3_get_addr_buffer(proto); if (ipaddr) { @@ -728,7 +647,7 @@ int qeth_l3_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto, if (qeth_l3_ip_from_hash(card, ipaddr)) rc = -EEXIST; else - qeth_l3_add_ip(card, ipaddr); + rc = qeth_l3_add_ip(card, ipaddr); spin_unlock_bh(&card->ip_lock); @@ -737,10 +656,11 @@ int qeth_l3_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto, return rc; } -void qeth_l3_del_vipa(struct qeth_card *card, enum qeth_prot_versions proto, - const u8 *addr) +int qeth_l3_del_vipa(struct qeth_card *card, enum qeth_prot_versions proto, + const u8 *addr) { struct qeth_ipaddr *ipaddr; + int rc; ipaddr = qeth_l3_get_addr_buffer(proto); if (ipaddr) { @@ -755,13 +675,14 @@ void qeth_l3_del_vipa(struct qeth_card *card, enum qeth_prot_versions proto, } ipaddr->type = QETH_IP_TYPE_VIPA; } else - return; + return -ENOMEM; spin_lock_bh(&card->ip_lock); - qeth_l3_delete_ip(card, ipaddr); + rc = qeth_l3_delete_ip(card, ipaddr); spin_unlock_bh(&card->ip_lock); kfree(ipaddr); + return rc; } /* @@ -771,7 +692,7 @@ int qeth_l3_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto, const u8 *addr) { struct qeth_ipaddr *ipaddr; - int rc = 0; + int rc; ipaddr = qeth_l3_get_addr_buffer(proto); if (ipaddr) { @@ -796,7 +717,7 @@ int qeth_l3_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto, if (qeth_l3_ip_from_hash(card, ipaddr)) rc = -EEXIST; else - qeth_l3_add_ip(card, ipaddr); + rc = qeth_l3_add_ip(card, ipaddr); spin_unlock_bh(&card->ip_lock); @@ -805,10 +726,11 @@ int qeth_l3_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto, return rc; } -void qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions proto, - const u8 *addr) +int qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions proto, + const u8 *addr) { struct qeth_ipaddr *ipaddr; + int rc; ipaddr = qeth_l3_get_addr_buffer(proto); if (ipaddr) { @@ -823,13 +745,14 @@ void qeth_l3_del_rxip(struct qeth_card *card, enum qeth_prot_versions proto, } ipaddr->type = QETH_IP_TYPE_RXIP; } else - return; + return -ENOMEM; spin_lock_bh(&card->ip_lock); - qeth_l3_delete_ip(card, ipaddr); + rc = qeth_l3_delete_ip(card, ipaddr); spin_unlock_bh(&card->ip_lock); kfree(ipaddr); + return rc; } static int qeth_l3_register_addr_entry(struct qeth_card *card, @@ -896,27 +819,6 @@ static int qeth_l3_deregister_addr_entry(struct qeth_card *card, return rc; } -static u8 qeth_l3_get_qeth_hdr_flags4(int cast_type) -{ - if (cast_type == RTN_MULTICAST) - return QETH_CAST_MULTICAST; - if (cast_type == RTN_BROADCAST) - return QETH_CAST_BROADCAST; - return QETH_CAST_UNICAST; -} - -static u8 qeth_l3_get_qeth_hdr_flags6(int cast_type) -{ - u8 ct = QETH_HDR_PASSTHRU | QETH_HDR_IPV6; - if (cast_type == RTN_MULTICAST) - return ct | QETH_CAST_MULTICAST; - if (cast_type == RTN_ANYCAST) - return ct | QETH_CAST_ANYCAST; - if (cast_type == RTN_BROADCAST) - return ct | QETH_CAST_BROADCAST; - return ct | QETH_CAST_UNICAST; -} - static int qeth_l3_setadapter_parms(struct qeth_card *card) { int rc = 0; @@ -933,7 +835,6 @@ static int qeth_l3_setadapter_parms(struct qeth_card *card) return rc; } -#ifdef CONFIG_QETH_IPV6 static int qeth_l3_send_simple_setassparms_ipv6(struct qeth_card *card, enum qeth_ipa_funcs ipa_func, __u16 cmd_code) { @@ -949,7 +850,6 @@ static int qeth_l3_send_simple_setassparms_ipv6(struct qeth_card *card, qeth_setassparms_cb, NULL); return rc; } -#endif static int qeth_l3_start_ipa_arp_processing(struct qeth_card *card) { @@ -1045,7 +945,6 @@ static int qeth_l3_start_ipa_multicast(struct qeth_card *card) return rc; } -#ifdef CONFIG_QETH_IPV6 static int qeth_l3_softsetup_ipv6(struct qeth_card *card) { int rc; @@ -1091,12 +990,9 @@ out: dev_info(&card->gdev->dev, "IPV6 enabled\n"); return 0; } -#endif static int qeth_l3_start_ipa_ipv6(struct qeth_card *card) { - int rc = 0; - QETH_CARD_TEXT(card, 3, "strtipv6"); if (!qeth_is_supported(card, IPA_IPV6)) { @@ -1104,10 +1000,7 @@ static int qeth_l3_start_ipa_ipv6(struct qeth_card *card) "IPv6 not supported on %s\n", QETH_CARD_IFNAME(card)); return 0; } -#ifdef CONFIG_QETH_IPV6 - rc = qeth_l3_softsetup_ipv6(card); -#endif - return rc ; + return qeth_l3_softsetup_ipv6(card); } static int qeth_l3_start_ipa_broadcast(struct qeth_card *card) @@ -1179,8 +1072,8 @@ static int qeth_l3_iqd_read_initial_mac_cb(struct qeth_card *card, cmd = (struct qeth_ipa_cmd *) data; if (cmd->hdr.return_code == 0) - memcpy(card->dev->dev_addr, - cmd->data.create_destroy_addr.unique_id, ETH_ALEN); + ether_addr_copy(card->dev->dev_addr, + cmd->data.create_destroy_addr.unique_id); else eth_random_addr(card->dev->dev_addr); @@ -1328,81 +1221,22 @@ qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd) return qeth_send_ipa_cmd(card, iob, qeth_diags_trace_cb, NULL); } -static void qeth_l3_get_mac_for_ipm(__be32 ipm, char *mac) -{ - ip_eth_mc_map(ipm, mac); -} - -static void qeth_l3_mark_all_mc_to_be_deleted(struct qeth_card *card) -{ - struct qeth_ipaddr *addr; - int i; - - hash_for_each(card->ip_mc_htable, i, addr, hnode) - addr->disp_flag = QETH_DISP_ADDR_DELETE; - -} - -static void qeth_l3_add_all_new_mc(struct qeth_card *card) -{ - struct qeth_ipaddr *addr; - struct hlist_node *tmp; - int i; - int rc; - - hash_for_each_safe(card->ip_mc_htable, i, tmp, addr, hnode) { - if (addr->disp_flag == QETH_DISP_ADDR_ADD) { - rc = qeth_l3_register_addr_entry(card, addr); - if (!rc || (rc == IPA_RC_LAN_OFFLINE)) - addr->ref_counter = 1; - else { - hash_del(&addr->hnode); - kfree(addr); - } - } - } - -} - -static void qeth_l3_delete_nonused_mc(struct qeth_card *card) -{ - struct qeth_ipaddr *addr; - struct hlist_node *tmp; - int i; - int rc; - - hash_for_each_safe(card->ip_mc_htable, i, tmp, addr, hnode) { - if (addr->disp_flag == QETH_DISP_ADDR_DELETE) { - rc = qeth_l3_deregister_addr_entry(card, addr); - if (!rc || (rc == IPA_RC_MC_ADDR_NOT_FOUND)) { - hash_del(&addr->hnode); - kfree(addr); - } - } - } - -} - - static void qeth_l3_add_mc_to_hash(struct qeth_card *card, struct in_device *in4_dev) { struct ip_mc_list *im4; struct qeth_ipaddr *tmp, *ipm; - char buf[MAX_ADDR_LEN]; QETH_CARD_TEXT(card, 4, "addmc"); tmp = qeth_l3_get_addr_buffer(QETH_PROT_IPV4); - if (!tmp) - return; + if (!tmp) + return; for (im4 = rcu_dereference(in4_dev->mc_list); im4 != NULL; im4 = rcu_dereference(im4->next_rcu)) { - qeth_l3_get_mac_for_ipm(im4->multiaddr, buf); - + ip_eth_mc_map(im4->multiaddr, tmp->mac); tmp->u.a4.addr = be32_to_cpu(im4->multiaddr); - memcpy(tmp->mac, buf, sizeof(tmp->mac)); tmp->is_multicast = 1; ipm = qeth_l3_ip_from_hash(card, tmp); @@ -1412,7 +1246,7 @@ qeth_l3_add_mc_to_hash(struct qeth_card *card, struct in_device *in4_dev) ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV4); if (!ipm) continue; - memcpy(ipm->mac, buf, sizeof(tmp->mac)); + ether_addr_copy(ipm->mac, tmp->mac); ipm->u.a4.addr = be32_to_cpu(im4->multiaddr); ipm->is_multicast = 1; ipm->disp_flag = QETH_DISP_ADDR_ADD; @@ -1466,25 +1300,21 @@ unlock: rcu_read_unlock(); } -#ifdef CONFIG_QETH_IPV6 -static void -qeth_l3_add_mc6_to_hash(struct qeth_card *card, struct inet6_dev *in6_dev) +static void qeth_l3_add_mc6_to_hash(struct qeth_card *card, + struct inet6_dev *in6_dev) { struct qeth_ipaddr *ipm; struct ifmcaddr6 *im6; struct qeth_ipaddr *tmp; - char buf[MAX_ADDR_LEN]; QETH_CARD_TEXT(card, 4, "addmc6"); tmp = qeth_l3_get_addr_buffer(QETH_PROT_IPV6); - if (!tmp) - return; + if (!tmp) + return; for (im6 = in6_dev->mc_list; im6 != NULL; im6 = im6->next) { - ndisc_mc_map(&im6->mca_addr, buf, in6_dev->dev, 0); - - memcpy(tmp->mac, buf, sizeof(tmp->mac)); + ipv6_eth_mc_map(&im6->mca_addr, tmp->mac); memcpy(&tmp->u.a6.addr, &im6->mca_addr.s6_addr, sizeof(struct in6_addr)); tmp->is_multicast = 1; @@ -1499,7 +1329,7 @@ qeth_l3_add_mc6_to_hash(struct qeth_card *card, struct inet6_dev *in6_dev) if (!ipm) continue; - memcpy(ipm->mac, buf, OSA_ADDR_LEN); + ether_addr_copy(ipm->mac, tmp->mac); memcpy(&ipm->u.a6.addr, &im6->mca_addr.s6_addr, sizeof(struct in6_addr)); ipm->is_multicast = 1; @@ -1560,7 +1390,6 @@ static void qeth_l3_add_multicast_ipv6(struct qeth_card *card) rcu_read_unlock(); in6_dev_put(in6_dev); } -#endif /* CONFIG_QETH_IPV6 */ static void qeth_l3_free_vlan_addresses4(struct qeth_card *card, unsigned short vid) @@ -1600,9 +1429,8 @@ out: } static void qeth_l3_free_vlan_addresses6(struct qeth_card *card, - unsigned short vid) + unsigned short vid) { -#ifdef CONFIG_QETH_IPV6 struct inet6_dev *in6_dev; struct inet6_ifaddr *ifa; struct qeth_ipaddr *addr; @@ -1637,7 +1465,6 @@ static void qeth_l3_free_vlan_addresses6(struct qeth_card *card, kfree(addr); out: in6_dev_put(in6_dev); -#endif /* CONFIG_QETH_IPV6 */ } static void qeth_l3_free_vlan_addresses(struct qeth_card *card, @@ -1672,44 +1499,31 @@ static int qeth_l3_vlan_rx_kill_vid(struct net_device *dev, /* unregister IP addresses of vlan device */ qeth_l3_free_vlan_addresses(card, vid); clear_bit(vid, card->active_vlans); - qeth_l3_set_multicast_list(card->dev); + qeth_l3_set_rx_mode(dev); return 0; } static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr *hdr) { - __u16 prot; - struct iphdr *ip_hdr; - unsigned char tg_addr[MAX_ADDR_LEN]; - if (!(hdr->hdr.l3.flags & QETH_HDR_PASSTHRU)) { - prot = (hdr->hdr.l3.flags & QETH_HDR_IPV6) ? ETH_P_IPV6 : - ETH_P_IP; + u16 prot = (hdr->hdr.l3.flags & QETH_HDR_IPV6) ? ETH_P_IPV6 : + ETH_P_IP; + unsigned char tg_addr[ETH_ALEN]; + + skb_reset_network_header(skb); switch (hdr->hdr.l3.flags & QETH_HDR_CAST_MASK) { case QETH_CAST_MULTICAST: - switch (prot) { -#ifdef CONFIG_QETH_IPV6 - case ETH_P_IPV6: - ndisc_mc_map((struct in6_addr *) - skb->data + 24, - tg_addr, card->dev, 0); - break; -#endif - case ETH_P_IP: - ip_hdr = (struct iphdr *)skb->data; - ip_eth_mc_map(ip_hdr->daddr, tg_addr); - break; - default: - memcpy(tg_addr, card->dev->broadcast, - card->dev->addr_len); - } + if (prot == ETH_P_IP) + ip_eth_mc_map(ip_hdr(skb)->daddr, tg_addr); + else + ipv6_eth_mc_map(&ipv6_hdr(skb)->daddr, tg_addr); + card->stats.multicast++; skb->pkt_type = PACKET_MULTICAST; break; case QETH_CAST_BROADCAST: - memcpy(tg_addr, card->dev->broadcast, - card->dev->addr_len); + ether_addr_copy(tg_addr, card->dev->broadcast); card->stats.multicast++; skb->pkt_type = PACKET_BROADCAST; break; @@ -1721,12 +1535,11 @@ static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, skb->pkt_type = PACKET_OTHERHOST; else skb->pkt_type = PACKET_HOST; - memcpy(tg_addr, card->dev->dev_addr, - card->dev->addr_len); + ether_addr_copy(tg_addr, card->dev->dev_addr); } if (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_SRC_MAC_ADDR) card->dev->header_ops->create(skb, card->dev, prot, - tg_addr, &hdr->hdr.l3.dest_addr[2], + tg_addr, &hdr->hdr.l3.next_hop.rx.src_mac, card->dev->addr_len); else card->dev->header_ops->create(skb, card->dev, prot, @@ -1741,7 +1554,7 @@ static void qeth_l3_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, QETH_HDR_EXT_INCLUDE_VLAN_TAG))) { u16 tag = (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_VLAN_FRAME) ? hdr->hdr.l3.vlan_id : - *((u16 *)&hdr->hdr.l3.dest_addr[12]); + hdr->hdr.l3.next_hop.rx.vlan_id; __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), tag); } @@ -1949,26 +1762,46 @@ qeth_l3_handle_promisc_mode(struct qeth_card *card) } } -static void qeth_l3_set_multicast_list(struct net_device *dev) +static void qeth_l3_set_rx_mode(struct net_device *dev) { struct qeth_card *card = dev->ml_priv; + struct qeth_ipaddr *addr; + struct hlist_node *tmp; + int i, rc; QETH_CARD_TEXT(card, 3, "setmulti"); if (qeth_threads_running(card, QETH_RECOVER_THREAD) && (card->state != CARD_STATE_UP)) return; if (!card->options.sniffer) { - spin_lock_bh(&card->mclock); - qeth_l3_mark_all_mc_to_be_deleted(card); - qeth_l3_add_multicast_ipv4(card); -#ifdef CONFIG_QETH_IPV6 qeth_l3_add_multicast_ipv6(card); -#endif - qeth_l3_delete_nonused_mc(card); - qeth_l3_add_all_new_mc(card); + + hash_for_each_safe(card->ip_mc_htable, i, tmp, addr, hnode) { + switch (addr->disp_flag) { + case QETH_DISP_ADDR_DELETE: + rc = qeth_l3_deregister_addr_entry(card, addr); + if (!rc || rc == IPA_RC_MC_ADDR_NOT_FOUND) { + hash_del(&addr->hnode); + kfree(addr); + } + break; + case QETH_DISP_ADDR_ADD: + rc = qeth_l3_register_addr_entry(card, addr); + if (rc && rc != IPA_RC_LAN_OFFLINE) { + hash_del(&addr->hnode); + kfree(addr); + break; + } + addr->ref_counter = 1; + /* fall through */ + default: + /* for next call to set_rx_mode(): */ + addr->disp_flag = QETH_DISP_ADDR_DELETE; + } + } spin_unlock_bh(&card->mclock); @@ -2237,12 +2070,10 @@ static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata) rc = -EFAULT; goto free_and_out; } -#ifdef CONFIG_QETH_IPV6 if (qinfo.mask_bits & QETH_QARP_WITH_IPV6) { /* fails in case of GuestLAN QDIO mode */ qeth_l3_query_arp_cache_info(card, QETH_PROT_IPV6, &qinfo); } -#endif if (copy_to_user(udata, qinfo.udata, qinfo.udata_len)) { QETH_CARD_TEXT(card, 4, "qactf"); rc = -EFAULT; @@ -2422,9 +2253,8 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return rc; } -static int qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb) +static int qeth_l3_get_cast_type(struct sk_buff *skb) { - int cast_type = RTN_UNSPEC; struct neighbour *n = NULL; struct dst_entry *dst; @@ -2433,48 +2263,34 @@ static int qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb) if (dst) n = dst_neigh_lookup_skb(dst, skb); if (n) { - cast_type = n->type; + int cast_type = n->type; + rcu_read_unlock(); neigh_release(n); if ((cast_type == RTN_BROADCAST) || (cast_type == RTN_MULTICAST) || (cast_type == RTN_ANYCAST)) return cast_type; - else - return RTN_UNSPEC; + return RTN_UNSPEC; } rcu_read_unlock(); - /* try something else */ + /* no neighbour (eg AF_PACKET), fall back to target's IP address ... */ if (be16_to_cpu(skb->protocol) == ETH_P_IPV6) - return (skb_network_header(skb)[24] == 0xff) ? - RTN_MULTICAST : 0; + return ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ? + RTN_MULTICAST : RTN_UNSPEC; else if (be16_to_cpu(skb->protocol) == ETH_P_IP) - return ((skb_network_header(skb)[16] & 0xf0) == 0xe0) ? - RTN_MULTICAST : 0; - /* ... */ - if (!memcmp(skb->data, skb->dev->broadcast, 6)) + return ipv4_is_multicast(ip_hdr(skb)->daddr) ? + RTN_MULTICAST : RTN_UNSPEC; + + /* ... and MAC address */ + if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest, skb->dev->broadcast)) return RTN_BROADCAST; - else { - u16 hdr_mac; - - 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)) - return RTN_MULTICAST; - break; - /* eth or so multicast? */ - default: - if ((hdr_mac == QETH_ETH_MAC_V4) || - (hdr_mac == QETH_ETH_MAC_V6)) - return RTN_MULTICAST; - } - } - return cast_type; + if (is_multicast_ether_addr(eth_hdr(skb)->h_dest)) + return RTN_MULTICAST; + + /* default to unicast */ + return RTN_UNSPEC; } static void qeth_l3_fill_af_iucv_hdr(struct qeth_card *card, @@ -2494,17 +2310,27 @@ static void qeth_l3_fill_af_iucv_hdr(struct qeth_card *card, daddr[0] = 0xfe; daddr[1] = 0x80; memcpy(&daddr[8], iucv_hdr->destUserID, 8); - memcpy(hdr->hdr.l3.dest_addr, daddr, 16); + memcpy(hdr->hdr.l3.next_hop.ipv6_addr, daddr, 16); } -static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, - struct sk_buff *skb, int ipv, int cast_type) +static u8 qeth_l3_cast_type_to_flag(int cast_type) { - struct dst_entry *dst; + if (cast_type == RTN_MULTICAST) + return QETH_CAST_MULTICAST; + if (cast_type == RTN_ANYCAST) + return QETH_CAST_ANYCAST; + if (cast_type == RTN_BROADCAST) + return QETH_CAST_BROADCAST; + return QETH_CAST_UNICAST; +} +static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, + struct sk_buff *skb, int ipv, int cast_type, + unsigned int data_len) +{ memset(hdr, 0, sizeof(struct qeth_hdr)); hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; - hdr->hdr.l3.ext_flags = 0; + hdr->hdr.l3.length = data_len; /* * before we're going to overwrite this location with next hop ip. @@ -2518,44 +2344,40 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, hdr->hdr.l3.vlan_id = skb_vlan_tag_get(skb); } - hdr->hdr.l3.length = skb->len - sizeof(struct qeth_hdr); + /* OSA only: */ + if (!ipv) { + hdr->hdr.l3.flags = QETH_HDR_PASSTHRU; + if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest, + skb->dev->broadcast)) + hdr->hdr.l3.flags |= QETH_CAST_BROADCAST; + else + hdr->hdr.l3.flags |= (cast_type == RTN_MULTICAST) ? + QETH_CAST_MULTICAST : QETH_CAST_UNICAST; + return; + } + hdr->hdr.l3.flags = qeth_l3_cast_type_to_flag(cast_type); rcu_read_lock(); - dst = skb_dst(skb); if (ipv == 4) { - struct rtable *rt = (struct rtable *) dst; - __be32 *pkey = &ip_hdr(skb)->daddr; - - if (rt && rt->rt_gateway) - pkey = &rt->rt_gateway; + struct rtable *rt = skb_rtable(skb); - /* IPv4 */ - hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags4(cast_type); - memset(hdr->hdr.l3.dest_addr, 0, 12); - *((__be32 *) (&hdr->hdr.l3.dest_addr[12])) = *pkey; - } else if (ipv == 6) { - struct rt6_info *rt = (struct rt6_info *) dst; - struct in6_addr *pkey = &ipv6_hdr(skb)->daddr; + *((__be32 *) &hdr->hdr.l3.next_hop.ipv4.addr) = (rt) ? + rt_nexthop(rt, ip_hdr(skb)->daddr) : + ip_hdr(skb)->daddr; + } else { + /* IPv6 */ + const struct rt6_info *rt = skb_rt6_info(skb); + const struct in6_addr *next_hop; if (rt && !ipv6_addr_any(&rt->rt6i_gateway)) - pkey = &rt->rt6i_gateway; + next_hop = &rt->rt6i_gateway; + else + next_hop = &ipv6_hdr(skb)->daddr; + memcpy(hdr->hdr.l3.next_hop.ipv6_addr, next_hop, 16); - /* IPv6 */ - hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags6(cast_type); - if (card->info.type == QETH_CARD_TYPE_IQD) - hdr->hdr.l3.flags &= ~QETH_HDR_PASSTHRU; - memcpy(hdr->hdr.l3.dest_addr, pkey, 16); - } else { - if (!memcmp(skb->data + sizeof(struct qeth_hdr), - skb->dev->broadcast, 6)) { - /* broadcast? */ - hdr->hdr.l3.flags = QETH_CAST_BROADCAST | - QETH_HDR_PASSTHRU; - } else { - hdr->hdr.l3.flags = (cast_type == RTN_MULTICAST) ? - QETH_CAST_MULTICAST | QETH_HDR_PASSTHRU : - QETH_CAST_UNICAST | QETH_HDR_PASSTHRU; - } + hdr->hdr.l3.flags |= QETH_HDR_IPV6; + if (card->info.type != QETH_CARD_TYPE_IQD) + hdr->hdr.l3.flags |= QETH_HDR_PASSTHRU; } rcu_read_unlock(); } @@ -2587,7 +2409,6 @@ static void qeth_tso_fill_header(struct qeth_card *card, /*fix header to TSO values ...*/ hdr->hdr.hdr.l3.id = QETH_HEADER_TYPE_TSO; - hdr->hdr.hdr.l3.length = skb->len - sizeof(struct qeth_hdr_tso); /*set values which are fix for the first approach ...*/ hdr->ext.hdr_tot_len = (__u16) sizeof(struct qeth_hdr_ext_tso); hdr->ext.imb_hdr_no = 1; @@ -2655,7 +2476,7 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, struct qeth_card *card = dev->ml_priv; struct sk_buff *new_skb = NULL; int ipv = qeth_get_ip_version(skb); - int cast_type = qeth_l3_get_cast_type(card, skb); + int cast_type = qeth_l3_get_cast_type(skb); struct qeth_qdio_out_q *queue = card->qdio.out_qs[card->qdio.do_prio_queueing || (cast_type && card->info.is_multicast_different) ? @@ -2748,21 +2569,23 @@ static netdev_tx_t qeth_l3_hard_start_xmit(struct sk_buff *skb, if (use_tso) { hdr = skb_push(new_skb, sizeof(struct qeth_hdr_tso)); memset(hdr, 0, sizeof(struct qeth_hdr_tso)); - qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type); + qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type, + new_skb->len - sizeof(struct qeth_hdr_tso)); qeth_tso_fill_header(card, hdr, new_skb); hdr_elements++; } else { if (data_offset < 0) { hdr = skb_push(new_skb, sizeof(struct qeth_hdr)); - qeth_l3_fill_header(card, hdr, new_skb, ipv, - cast_type); + qeth_l3_fill_header(card, hdr, new_skb, ipv, cast_type, + new_skb->len - + sizeof(struct qeth_hdr)); } else { if (be16_to_cpu(new_skb->protocol) == ETH_P_AF_IUCV) qeth_l3_fill_af_iucv_hdr(card, hdr, new_skb); else { qeth_l3_fill_header(card, hdr, new_skb, ipv, - cast_type); - hdr->hdr.l3.length = new_skb->len - data_offset; + cast_type, + new_skb->len - data_offset); } } @@ -2930,7 +2753,7 @@ static const struct net_device_ops qeth_l3_netdev_ops = { .ndo_get_stats = qeth_get_stats, .ndo_start_xmit = qeth_l3_hard_start_xmit, .ndo_validate_addr = eth_validate_addr, - .ndo_set_rx_mode = qeth_l3_set_multicast_list, + .ndo_set_rx_mode = qeth_l3_set_rx_mode, .ndo_do_ioctl = qeth_do_ioctl, .ndo_change_mtu = qeth_change_mtu, .ndo_fix_features = qeth_fix_features, @@ -2947,7 +2770,7 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = { .ndo_start_xmit = qeth_l3_hard_start_xmit, .ndo_features_check = qeth_features_check, .ndo_validate_addr = eth_validate_addr, - .ndo_set_rx_mode = qeth_l3_set_multicast_list, + .ndo_set_rx_mode = qeth_l3_set_rx_mode, .ndo_do_ioctl = qeth_do_ioctl, .ndo_change_mtu = qeth_change_mtu, .ndo_fix_features = qeth_fix_features, @@ -3145,7 +2968,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) __qeth_l3_open(card->dev); else dev_open(card->dev); - qeth_l3_set_multicast_list(card->dev); + qeth_l3_set_rx_mode(card->dev); qeth_recover_features(card->dev); rtnl_unlock(); } @@ -3371,10 +3194,6 @@ static struct notifier_block qeth_l3_ip_notifier = { NULL, }; -#ifdef CONFIG_QETH_IPV6 -/** - * IPv6 event handler - */ static int qeth_l3_ip6_event(struct notifier_block *this, unsigned long event, void *ptr) { @@ -3419,7 +3238,6 @@ static struct notifier_block qeth_l3_ip6_notifier = { qeth_l3_ip6_event, NULL, }; -#endif static int qeth_l3_register_notifiers(void) { @@ -3429,35 +3247,25 @@ static int qeth_l3_register_notifiers(void) rc = register_inetaddr_notifier(&qeth_l3_ip_notifier); if (rc) return rc; -#ifdef CONFIG_QETH_IPV6 rc = register_inet6addr_notifier(&qeth_l3_ip6_notifier); if (rc) { unregister_inetaddr_notifier(&qeth_l3_ip_notifier); return rc; } -#else - pr_warn("There is no IPv6 support for the layer 3 discipline\n"); -#endif return 0; } static void qeth_l3_unregister_notifiers(void) { - QETH_DBF_TEXT(SETUP, 5, "unregnot"); WARN_ON(unregister_inetaddr_notifier(&qeth_l3_ip_notifier)); -#ifdef CONFIG_QETH_IPV6 WARN_ON(unregister_inet6addr_notifier(&qeth_l3_ip6_notifier)); -#endif /* QETH_IPV6 */ } static int __init qeth_l3_init(void) { - int rc = 0; - pr_info("register layer 3 discipline\n"); - rc = qeth_l3_register_notifiers(); - return rc; + return qeth_l3_register_notifiers(); } static void __exit qeth_l3_exit(void) diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index 6ea2b528a64e..a645cfe66ddf 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c @@ -10,11 +10,23 @@ #include <linux/slab.h> #include <asm/ebcdic.h> #include <linux/hashtable.h> +#include <linux/inet.h> #include "qeth_l3.h" #define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \ struct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store) +static int qeth_l3_string_to_ipaddr(const char *buf, + enum qeth_prot_versions proto, u8 *addr) +{ + const char *end; + + if ((proto == QETH_PROT_IPV4 && !in4_pton(buf, -1, addr, -1, &end)) || + (proto == QETH_PROT_IPV6 && !in6_pton(buf, -1, addr, -1, &end))) + return -EINVAL; + return 0; +} + static ssize_t qeth_l3_dev_route_show(struct qeth_card *card, struct qeth_routing_info *route, char *buf) { @@ -262,7 +274,7 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev, struct qeth_card *card = dev_get_drvdata(dev); struct qeth_ipaddr *addr; char *tmp; - int i; + int rc, i; if (!card) return -EINVAL; @@ -331,11 +343,11 @@ static ssize_t qeth_l3_dev_hsuid_store(struct device *dev, return -ENOMEM; spin_lock_bh(&card->ip_lock); - qeth_l3_add_ip(card, addr); + rc = qeth_l3_add_ip(card, addr); spin_unlock_bh(&card->ip_lock); kfree(addr); - return count; + return rc ? rc : count; } static DEVICE_ATTR(hsuid, 0644, qeth_l3_dev_hsuid_show, @@ -573,7 +585,7 @@ static ssize_t qeth_l3_dev_ipato_del_store(const char *buf, size_t count, mutex_lock(&card->conf_mutex); rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits); if (!rc) - qeth_l3_del_ipato_entry(card, proto, addr, mask_bits); + rc = qeth_l3_del_ipato_entry(card, proto, addr, mask_bits); mutex_unlock(&card->conf_mutex); return rc ? rc : count; } @@ -693,22 +705,25 @@ static const struct attribute_group qeth_device_ipato_group = { .attrs = qeth_ipato_device_attrs, }; -static ssize_t qeth_l3_dev_vipa_add_show(char *buf, struct qeth_card *card, - enum qeth_prot_versions proto) +static ssize_t qeth_l3_dev_ip_add_show(struct device *dev, char *buf, + enum qeth_prot_versions proto, + enum qeth_ip_types type) { + struct qeth_card *card = dev_get_drvdata(dev); struct qeth_ipaddr *ipaddr; char addr_str[40]; int str_len = 0; int entry_len; /* length of 1 entry string, differs between v4 and v6 */ int i; + if (!card) + return -EINVAL; + entry_len = (proto == QETH_PROT_IPV4)? 12 : 40; entry_len += 2; /* \n + terminator */ spin_lock_bh(&card->ip_lock); hash_for_each(card->ip_htable, i, ipaddr, hnode) { - if (ipaddr->proto != proto) - continue; - if (ipaddr->type != QETH_IP_TYPE_VIPA) + if (ipaddr->proto != proto || ipaddr->type != type) continue; /* String must not be longer than PAGE_SIZE. So we check if * string length gets near PAGE_SIZE. Then we can savely display @@ -727,14 +742,11 @@ static ssize_t qeth_l3_dev_vipa_add_show(char *buf, struct qeth_card *card, } static ssize_t qeth_l3_dev_vipa_add4_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { - struct qeth_card *card = dev_get_drvdata(dev); - - if (!card) - return -EINVAL; - - return qeth_l3_dev_vipa_add_show(buf, card, QETH_PROT_IPV4); + return qeth_l3_dev_ip_add_show(dev, buf, QETH_PROT_IPV4, + QETH_IP_TYPE_VIPA); } static int qeth_l3_parse_vipae(const char *buf, enum qeth_prot_versions proto, @@ -784,7 +796,7 @@ static ssize_t qeth_l3_dev_vipa_del_store(const char *buf, size_t count, mutex_lock(&card->conf_mutex); rc = qeth_l3_parse_vipae(buf, proto, addr); if (!rc) - qeth_l3_del_vipa(card, proto, addr); + rc = qeth_l3_del_vipa(card, proto, addr); mutex_unlock(&card->conf_mutex); return rc ? rc : count; } @@ -804,14 +816,11 @@ static QETH_DEVICE_ATTR(vipa_del4, del4, 0200, NULL, qeth_l3_dev_vipa_del4_store); static ssize_t qeth_l3_dev_vipa_add6_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { - struct qeth_card *card = dev_get_drvdata(dev); - - if (!card) - return -EINVAL; - - return qeth_l3_dev_vipa_add_show(buf, card, QETH_PROT_IPV6); + return qeth_l3_dev_ip_add_show(dev, buf, QETH_PROT_IPV6, + QETH_IP_TYPE_VIPA); } static ssize_t qeth_l3_dev_vipa_add6_store(struct device *dev, @@ -856,48 +865,12 @@ static const struct attribute_group qeth_device_vipa_group = { .attrs = qeth_vipa_device_attrs, }; -static ssize_t qeth_l3_dev_rxip_add_show(char *buf, struct qeth_card *card, - enum qeth_prot_versions proto) -{ - struct qeth_ipaddr *ipaddr; - char addr_str[40]; - int str_len = 0; - int entry_len; /* length of 1 entry string, differs between v4 and v6 */ - int i; - - entry_len = (proto == QETH_PROT_IPV4)? 12 : 40; - entry_len += 2; /* \n + terminator */ - spin_lock_bh(&card->ip_lock); - hash_for_each(card->ip_htable, i, ipaddr, hnode) { - if (ipaddr->proto != proto) - continue; - if (ipaddr->type != QETH_IP_TYPE_RXIP) - continue; - /* String must not be longer than PAGE_SIZE. So we check if - * string length gets near PAGE_SIZE. Then we can savely display - * the next IPv6 address (worst case, compared to IPv4) */ - if ((PAGE_SIZE - str_len) <= entry_len) - break; - qeth_l3_ipaddr_to_string(proto, (const u8 *)&ipaddr->u, - addr_str); - str_len += snprintf(buf + str_len, PAGE_SIZE - str_len, "%s\n", - addr_str); - } - spin_unlock_bh(&card->ip_lock); - str_len += snprintf(buf + str_len, PAGE_SIZE - str_len, "\n"); - - return str_len; -} - static ssize_t qeth_l3_dev_rxip_add4_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { - struct qeth_card *card = dev_get_drvdata(dev); - - if (!card) - return -EINVAL; - - return qeth_l3_dev_rxip_add_show(buf, card, QETH_PROT_IPV4); + return qeth_l3_dev_ip_add_show(dev, buf, QETH_PROT_IPV4, + QETH_IP_TYPE_RXIP); } static int qeth_l3_parse_rxipe(const char *buf, enum qeth_prot_versions proto, @@ -964,7 +937,7 @@ static ssize_t qeth_l3_dev_rxip_del_store(const char *buf, size_t count, mutex_lock(&card->conf_mutex); rc = qeth_l3_parse_rxipe(buf, proto, addr); if (!rc) - qeth_l3_del_rxip(card, proto, addr); + rc = qeth_l3_del_rxip(card, proto, addr); mutex_unlock(&card->conf_mutex); return rc ? rc : count; } @@ -984,14 +957,11 @@ static QETH_DEVICE_ATTR(rxip_del4, del4, 0200, NULL, qeth_l3_dev_rxip_del4_store); static ssize_t qeth_l3_dev_rxip_add6_show(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { - struct qeth_card *card = dev_get_drvdata(dev); - - if (!card) - return -EINVAL; - - return qeth_l3_dev_rxip_add_show(buf, card, QETH_PROT_IPV6); + return qeth_l3_dev_ip_add_show(dev, buf, QETH_PROT_IPV6, + QETH_IP_TYPE_RXIP); } static ssize_t qeth_l3_dev_rxip_add6_store(struct device *dev, |