Merge 4.4.219 into android-4.4-p
Changes in 4.4.219
drm/bochs: downgrade pci_request_region failure from error to warning
ipv4: fix a RCU-list lock in fib_triestat_seq_show
net, ip_tunnel: fix interface lookup with no key
sctp: fix possibly using a bad saddr with a given dst
l2tp: Correctly return -EBADF from pppol2tp_getname.
net: l2tp: Make l2tp_ip6 namespace aware
l2tp: fix race in l2tp_recv_common()
l2tp: ensure session can't get removed during pppol2tp_session_ioctl()
l2tp: fix duplicate session creation
l2tp: Refactor the codes with existing macros instead of literal number
l2tp: ensure sessions are freed after their PPPOL2TP socket
l2tp: fix race between l2tp_session_delete() and l2tp_tunnel_closeall()
usb: gadget: uac2: Drop unused device qualifier descriptor
usb: gadget: printer: Drop unused device qualifier descriptor
padata: always acquire cpu_hotplug_lock before pinst->lock
mm: mempolicy: require at least one nodeid for MPOL_PREFERRED
net: stmmac: dwmac1000: fix out-of-bounds mac address reg setting
slcan: Don't transmit uninitialized stack data in padding
random: always use batched entropy for get_random_u{32,64}
tools/accounting/getdelays.c: fix netlink attribute length
power: supply: axp288_charger: Fix unchecked return value
xen-netfront: Fix mismatched rtnl_unlock
xen-netfront: Update features after registering netdev
ASoC: jz4740-i2s: Fix divider written at incorrect offset in register
IB/hfi1: Call kobject_put() when kobject_init_and_add() fails
Bluetooth: RFCOMM: fix ODEBUG bug in rfcomm_dev_ioctl
RDMA/cm: Update num_paths in cma_resolve_iboe_route error flow
clk: qcom: rcg: Return failure for RCG update
drm_dp_mst_topology: fix broken drm_dp_sideband_parse_remote_dpcd_read()
Linux 4.4.219
Change-Id: Ic6486cf91cf823d392cd4ac467135748f3e13e8c
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
@@ -135,7 +135,7 @@ static int send_cmd(int sd, __u16 nlmsg_type, __u32 nlmsg_pid,
|
||||
msg.g.version = 0x1;
|
||||
na = (struct nlattr *) GENLMSG_DATA(&msg);
|
||||
na->nla_type = nla_type;
|
||||
na->nla_len = nla_len + 1 + NLA_HDRLEN;
|
||||
na->nla_len = nla_len + NLA_HDRLEN;
|
||||
memcpy(NLA_DATA(na), nla_data, nla_len);
|
||||
msg.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
|
||||
|
||||
|
||||
2
Makefile
2
Makefile
@@ -1,6 +1,6 @@
|
||||
VERSION = 4
|
||||
PATCHLEVEL = 4
|
||||
SUBLEVEL = 218
|
||||
SUBLEVEL = 219
|
||||
EXTRAVERSION =
|
||||
NAME = Blurry Fish Butt
|
||||
|
||||
|
||||
@@ -1824,9 +1824,6 @@ unsigned int get_random_int(void)
|
||||
__u32 *hash;
|
||||
unsigned int ret;
|
||||
|
||||
if (arch_get_random_int(&ret))
|
||||
return ret;
|
||||
|
||||
hash = get_cpu_var(get_random_int_hash);
|
||||
|
||||
hash[0] += current->pid + jiffies + random_get_entropy();
|
||||
@@ -1846,9 +1843,6 @@ unsigned long get_random_long(void)
|
||||
__u32 *hash;
|
||||
unsigned long ret;
|
||||
|
||||
if (arch_get_random_long(&ret))
|
||||
return ret;
|
||||
|
||||
hash = get_cpu_var(get_random_int_hash);
|
||||
|
||||
hash[0] += current->pid + jiffies + random_get_entropy();
|
||||
|
||||
@@ -107,7 +107,7 @@ static int update_config(struct clk_rcg2 *rcg)
|
||||
}
|
||||
|
||||
WARN(1, "%s: rcg didn't update its configuration.", name);
|
||||
return 0;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index)
|
||||
|
||||
@@ -97,10 +97,8 @@ int bochs_hw_init(struct drm_device *dev, uint32_t flags)
|
||||
size = min(size, mem);
|
||||
}
|
||||
|
||||
if (pci_request_region(pdev, 0, "bochs-drm") != 0) {
|
||||
DRM_ERROR("Cannot request framebuffer\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
if (pci_request_region(pdev, 0, "bochs-drm") != 0)
|
||||
DRM_WARN("Cannot request framebuffer, boot fb still active?\n");
|
||||
|
||||
bochs->fb_map = ioremap(addr, size);
|
||||
if (bochs->fb_map == NULL) {
|
||||
|
||||
@@ -431,6 +431,7 @@ static bool drm_dp_sideband_parse_remote_dpcd_read(struct drm_dp_sideband_msg_rx
|
||||
if (idx > raw->curlen)
|
||||
goto fail_len;
|
||||
repmsg->u.remote_dpcd_read_ack.num_bytes = raw->msg[idx];
|
||||
idx++;
|
||||
if (idx > raw->curlen)
|
||||
goto fail_len;
|
||||
|
||||
|
||||
@@ -2378,6 +2378,7 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
|
||||
err2:
|
||||
kfree(route->path_rec);
|
||||
route->path_rec = NULL;
|
||||
route->num_paths = 0;
|
||||
err1:
|
||||
kfree(work);
|
||||
return ret;
|
||||
|
||||
@@ -147,7 +147,7 @@ static void slc_bump(struct slcan *sl)
|
||||
u32 tmpid;
|
||||
char *cmd = sl->rbuff;
|
||||
|
||||
cf.can_id = 0;
|
||||
memset(&cf, 0, sizeof(cf));
|
||||
|
||||
switch (*cmd) {
|
||||
case 'r':
|
||||
@@ -186,8 +186,6 @@ static void slc_bump(struct slcan *sl)
|
||||
else
|
||||
return;
|
||||
|
||||
*(u64 *) (&cf.data) = 0; /* clear payload */
|
||||
|
||||
/* RTR frames may have a dlc > 0 but they never have any data bytes */
|
||||
if (!(cf.can_id & CAN_RTR_FLAG)) {
|
||||
for (i = 0; i < cf.can_dlc; i++) {
|
||||
|
||||
@@ -188,7 +188,7 @@ static void dwmac1000_set_filter(struct mac_device_info *hw,
|
||||
reg++;
|
||||
}
|
||||
|
||||
while (reg <= perfect_addr_number) {
|
||||
while (reg < perfect_addr_number) {
|
||||
writel(0, ioaddr + GMAC_ADDR_HIGH(reg));
|
||||
writel(0, ioaddr + GMAC_ADDR_LOW(reg));
|
||||
reg++;
|
||||
|
||||
@@ -1835,7 +1835,7 @@ static int talk_to_netback(struct xenbus_device *dev,
|
||||
err = xen_net_read_mac(dev, info->netdev->dev_addr);
|
||||
if (err) {
|
||||
xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
|
||||
goto out;
|
||||
goto out_unlocked;
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
@@ -1950,6 +1950,7 @@ abort_transaction_no_dev_fatal:
|
||||
xennet_destroy_queues(info);
|
||||
out:
|
||||
rtnl_unlock();
|
||||
out_unlocked:
|
||||
device_unregister(&dev->dev);
|
||||
return err;
|
||||
}
|
||||
@@ -1981,10 +1982,6 @@ static int xennet_connect(struct net_device *dev)
|
||||
/* talk_to_netback() sets the correct number of queues */
|
||||
num_queues = dev->real_num_tx_queues;
|
||||
|
||||
rtnl_lock();
|
||||
netdev_update_features(dev);
|
||||
rtnl_unlock();
|
||||
|
||||
if (dev->reg_state == NETREG_UNINITIALIZED) {
|
||||
err = register_netdev(dev);
|
||||
if (err) {
|
||||
@@ -1994,6 +1991,10 @@ static int xennet_connect(struct net_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
rtnl_lock();
|
||||
netdev_update_features(dev);
|
||||
rtnl_unlock();
|
||||
|
||||
/*
|
||||
* All public and private state should now be sane. Get
|
||||
* ready to start sending and receiving packets and give the driver
|
||||
|
||||
@@ -883,6 +883,10 @@ static int axp288_charger_probe(struct platform_device *pdev)
|
||||
/* Register charger interrupts */
|
||||
for (i = 0; i < CHRG_INTR_END; i++) {
|
||||
pirq = platform_get_irq(info->pdev, i);
|
||||
if (pirq < 0) {
|
||||
dev_err(&pdev->dev, "Failed to get IRQ: %d\n", pirq);
|
||||
return pirq;
|
||||
}
|
||||
info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq);
|
||||
if (info->irq[i] < 0) {
|
||||
dev_warn(&info->pdev->dev,
|
||||
|
||||
@@ -620,7 +620,11 @@ int hfi1_create_port_files(struct ib_device *ibdev, u8 port_num,
|
||||
dd_dev_err(dd,
|
||||
"Skipping sc2vl sysfs info, (err %d) port %u\n",
|
||||
ret, port_num);
|
||||
goto bail;
|
||||
/*
|
||||
* Based on the documentation for kobject_init_and_add(), the
|
||||
* caller should call kobject_put even if this call fails.
|
||||
*/
|
||||
goto bail_sc2vl;
|
||||
}
|
||||
kobject_uevent(&ppd->sc2vl_kobj, KOBJ_ADD);
|
||||
|
||||
@@ -630,7 +634,7 @@ int hfi1_create_port_files(struct ib_device *ibdev, u8 port_num,
|
||||
dd_dev_err(dd,
|
||||
"Skipping sl2sc sysfs info, (err %d) port %u\n",
|
||||
ret, port_num);
|
||||
goto bail_sc2vl;
|
||||
goto bail_sl2sc;
|
||||
}
|
||||
kobject_uevent(&ppd->sl2sc_kobj, KOBJ_ADD);
|
||||
|
||||
@@ -640,7 +644,7 @@ int hfi1_create_port_files(struct ib_device *ibdev, u8 port_num,
|
||||
dd_dev_err(dd,
|
||||
"Skipping vl2mtu sysfs info, (err %d) port %u\n",
|
||||
ret, port_num);
|
||||
goto bail_sl2sc;
|
||||
goto bail_vl2mtu;
|
||||
}
|
||||
kobject_uevent(&ppd->vl2mtu_kobj, KOBJ_ADD);
|
||||
|
||||
@@ -651,7 +655,7 @@ int hfi1_create_port_files(struct ib_device *ibdev, u8 port_num,
|
||||
dd_dev_err(dd,
|
||||
"Skipping Congestion Control sysfs info, (err %d) port %u\n",
|
||||
ret, port_num);
|
||||
goto bail_vl2mtu;
|
||||
goto bail_cc;
|
||||
}
|
||||
|
||||
kobject_uevent(&ppd->pport_cc_kobj, KOBJ_ADD);
|
||||
@@ -691,7 +695,6 @@ bail_sl2sc:
|
||||
kobject_put(&ppd->sl2sc_kobj);
|
||||
bail_sc2vl:
|
||||
kobject_put(&ppd->sc2vl_kobj);
|
||||
bail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -161,14 +161,6 @@ static struct usb_endpoint_descriptor hs_ep_out_desc = {
|
||||
.wMaxPacketSize = cpu_to_le16(512)
|
||||
};
|
||||
|
||||
static struct usb_qualifier_descriptor dev_qualifier = {
|
||||
.bLength = sizeof(dev_qualifier),
|
||||
.bDescriptorType = USB_DT_DEVICE_QUALIFIER,
|
||||
.bcdUSB = cpu_to_le16(0x0200),
|
||||
.bDeviceClass = USB_CLASS_PRINTER,
|
||||
.bNumConfigurations = 1
|
||||
};
|
||||
|
||||
static struct usb_descriptor_header *hs_printer_function[] = {
|
||||
(struct usb_descriptor_header *) &intf_desc,
|
||||
(struct usb_descriptor_header *) &hs_ep_in_desc,
|
||||
|
||||
@@ -598,18 +598,6 @@ static struct usb_gadget_strings *fn_strings[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct usb_qualifier_descriptor devqual_desc = {
|
||||
.bLength = sizeof devqual_desc,
|
||||
.bDescriptorType = USB_DT_DEVICE_QUALIFIER,
|
||||
|
||||
.bcdUSB = cpu_to_le16(0x200),
|
||||
.bDeviceClass = USB_CLASS_MISC,
|
||||
.bDeviceSubClass = 0x02,
|
||||
.bDeviceProtocol = 0x01,
|
||||
.bNumConfigurations = 1,
|
||||
.bRESERVED = 0,
|
||||
};
|
||||
|
||||
static struct usb_interface_assoc_descriptor iad_desc = {
|
||||
.bLength = sizeof iad_desc,
|
||||
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
|
||||
|
||||
@@ -640,8 +640,8 @@ int padata_set_cpumask(struct padata_instance *pinst, int cpumask_type,
|
||||
struct cpumask *serial_mask, *parallel_mask;
|
||||
int err = -EINVAL;
|
||||
|
||||
mutex_lock(&pinst->lock);
|
||||
get_online_cpus();
|
||||
mutex_lock(&pinst->lock);
|
||||
|
||||
switch (cpumask_type) {
|
||||
case PADATA_CPU_PARALLEL:
|
||||
@@ -659,8 +659,8 @@ int padata_set_cpumask(struct padata_instance *pinst, int cpumask_type,
|
||||
err = __padata_set_cpumasks(pinst, parallel_mask, serial_mask);
|
||||
|
||||
out:
|
||||
put_online_cpus();
|
||||
mutex_unlock(&pinst->lock);
|
||||
put_online_cpus();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -2724,7 +2724,9 @@ int mpol_parse_str(char *str, struct mempolicy **mpol)
|
||||
switch (mode) {
|
||||
case MPOL_PREFERRED:
|
||||
/*
|
||||
* Insist on a nodelist of one node only
|
||||
* Insist on a nodelist of one node only, although later
|
||||
* we use first_node(nodes) to grab a single node, so here
|
||||
* nodelist (or nodes) cannot be empty.
|
||||
*/
|
||||
if (nodelist) {
|
||||
char *rest = nodelist;
|
||||
@@ -2732,6 +2734,8 @@ int mpol_parse_str(char *str, struct mempolicy **mpol)
|
||||
rest++;
|
||||
if (*rest)
|
||||
goto out;
|
||||
if (nodes_empty(nodes))
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
case MPOL_INTERLEAVE:
|
||||
|
||||
@@ -413,10 +413,8 @@ static int __rfcomm_create_dev(struct sock *sk, void __user *arg)
|
||||
dlc = rfcomm_dlc_exists(&req.src, &req.dst, req.channel);
|
||||
if (IS_ERR(dlc))
|
||||
return PTR_ERR(dlc);
|
||||
else if (dlc) {
|
||||
rfcomm_dlc_put(dlc);
|
||||
if (dlc)
|
||||
return -EBUSY;
|
||||
}
|
||||
dlc = rfcomm_dlc_alloc(GFP_KERNEL);
|
||||
if (!dlc)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -2230,6 +2230,7 @@ static int fib_triestat_seq_show(struct seq_file *seq, void *v)
|
||||
" %Zd bytes, size of tnode: %Zd bytes.\n",
|
||||
LEAF_SIZE, TNODE_SIZE(0));
|
||||
|
||||
rcu_read_lock();
|
||||
for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
|
||||
struct hlist_head *head = &net->ipv4.fib_table_hash[h];
|
||||
struct fib_table *tb;
|
||||
@@ -2249,7 +2250,9 @@ static int fib_triestat_seq_show(struct seq_file *seq, void *v)
|
||||
trie_show_usage(seq, t->stats);
|
||||
#endif
|
||||
}
|
||||
cond_resched_rcu();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -155,11 +155,8 @@ struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn,
|
||||
cand = t;
|
||||
}
|
||||
|
||||
if (flags & TUNNEL_NO_KEY)
|
||||
goto skip_key_lookup;
|
||||
|
||||
hlist_for_each_entry_rcu(t, head, hash_node) {
|
||||
if (t->parms.i_key != key ||
|
||||
if ((!(flags & TUNNEL_NO_KEY) && t->parms.i_key != key) ||
|
||||
t->parms.iph.saddr != 0 ||
|
||||
t->parms.iph.daddr != 0 ||
|
||||
!(t->dev->flags & IFF_UP))
|
||||
@@ -171,7 +168,6 @@ struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn,
|
||||
cand = t;
|
||||
}
|
||||
|
||||
skip_key_lookup:
|
||||
if (cand)
|
||||
return cand;
|
||||
|
||||
|
||||
@@ -277,6 +277,55 @@ struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunn
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2tp_session_find);
|
||||
|
||||
/* Like l2tp_session_find() but takes a reference on the returned session.
|
||||
* Optionally calls session->ref() too if do_ref is true.
|
||||
*/
|
||||
struct l2tp_session *l2tp_session_get(struct net *net,
|
||||
struct l2tp_tunnel *tunnel,
|
||||
u32 session_id, bool do_ref)
|
||||
{
|
||||
struct hlist_head *session_list;
|
||||
struct l2tp_session *session;
|
||||
|
||||
if (!tunnel) {
|
||||
struct l2tp_net *pn = l2tp_pernet(net);
|
||||
|
||||
session_list = l2tp_session_id_hash_2(pn, session_id);
|
||||
|
||||
rcu_read_lock_bh();
|
||||
hlist_for_each_entry_rcu(session, session_list, global_hlist) {
|
||||
if (session->session_id == session_id) {
|
||||
l2tp_session_inc_refcount(session);
|
||||
if (do_ref && session->ref)
|
||||
session->ref(session);
|
||||
rcu_read_unlock_bh();
|
||||
|
||||
return session;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock_bh();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
session_list = l2tp_session_id_hash(tunnel, session_id);
|
||||
read_lock_bh(&tunnel->hlist_lock);
|
||||
hlist_for_each_entry(session, session_list, hlist) {
|
||||
if (session->session_id == session_id) {
|
||||
l2tp_session_inc_refcount(session);
|
||||
if (do_ref && session->ref)
|
||||
session->ref(session);
|
||||
read_unlock_bh(&tunnel->hlist_lock);
|
||||
|
||||
return session;
|
||||
}
|
||||
}
|
||||
read_unlock_bh(&tunnel->hlist_lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2tp_session_get);
|
||||
|
||||
struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth,
|
||||
bool do_ref)
|
||||
{
|
||||
@@ -328,6 +377,48 @@ struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2tp_session_find_by_ifname);
|
||||
|
||||
static int l2tp_session_add_to_tunnel(struct l2tp_tunnel *tunnel,
|
||||
struct l2tp_session *session)
|
||||
{
|
||||
struct l2tp_session *session_walk;
|
||||
struct hlist_head *g_head;
|
||||
struct hlist_head *head;
|
||||
struct l2tp_net *pn;
|
||||
|
||||
head = l2tp_session_id_hash(tunnel, session->session_id);
|
||||
|
||||
write_lock_bh(&tunnel->hlist_lock);
|
||||
hlist_for_each_entry(session_walk, head, hlist)
|
||||
if (session_walk->session_id == session->session_id)
|
||||
goto exist;
|
||||
|
||||
if (tunnel->version == L2TP_HDR_VER_3) {
|
||||
pn = l2tp_pernet(tunnel->l2tp_net);
|
||||
g_head = l2tp_session_id_hash_2(l2tp_pernet(tunnel->l2tp_net),
|
||||
session->session_id);
|
||||
|
||||
spin_lock_bh(&pn->l2tp_session_hlist_lock);
|
||||
hlist_for_each_entry(session_walk, g_head, global_hlist)
|
||||
if (session_walk->session_id == session->session_id)
|
||||
goto exist_glob;
|
||||
|
||||
hlist_add_head_rcu(&session->global_hlist, g_head);
|
||||
spin_unlock_bh(&pn->l2tp_session_hlist_lock);
|
||||
}
|
||||
|
||||
hlist_add_head(&session->hlist, head);
|
||||
write_unlock_bh(&tunnel->hlist_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
exist_glob:
|
||||
spin_unlock_bh(&pn->l2tp_session_hlist_lock);
|
||||
exist:
|
||||
write_unlock_bh(&tunnel->hlist_lock);
|
||||
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
/* Lookup a tunnel by id
|
||||
*/
|
||||
struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id)
|
||||
@@ -636,6 +727,9 @@ discard:
|
||||
* a data (not control) frame before coming here. Fields up to the
|
||||
* session-id have already been parsed and ptr points to the data
|
||||
* after the session-id.
|
||||
*
|
||||
* session->ref() must have been called prior to l2tp_recv_common().
|
||||
* session->deref() will be called automatically after skb is processed.
|
||||
*/
|
||||
void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
|
||||
unsigned char *ptr, unsigned char *optr, u16 hdrflags,
|
||||
@@ -645,14 +739,6 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
|
||||
int offset;
|
||||
u32 ns, nr;
|
||||
|
||||
/* The ref count is increased since we now hold a pointer to
|
||||
* the session. Take care to decrement the refcnt when exiting
|
||||
* this function from now on...
|
||||
*/
|
||||
l2tp_session_inc_refcount(session);
|
||||
if (session->ref)
|
||||
(*session->ref)(session);
|
||||
|
||||
/* Parse and check optional cookie */
|
||||
if (session->peer_cookie_len > 0) {
|
||||
if (memcmp(ptr, &session->peer_cookie[0], session->peer_cookie_len)) {
|
||||
@@ -803,8 +889,6 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
|
||||
/* Try to dequeue as many skbs from reorder_q as we can. */
|
||||
l2tp_recv_dequeue(session);
|
||||
|
||||
l2tp_session_dec_refcount(session);
|
||||
|
||||
return;
|
||||
|
||||
discard:
|
||||
@@ -813,8 +897,6 @@ discard:
|
||||
|
||||
if (session->deref)
|
||||
(*session->deref)(session);
|
||||
|
||||
l2tp_session_dec_refcount(session);
|
||||
}
|
||||
EXPORT_SYMBOL(l2tp_recv_common);
|
||||
|
||||
@@ -921,8 +1003,14 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
|
||||
}
|
||||
|
||||
/* Find the session context */
|
||||
session = l2tp_session_find(tunnel->l2tp_net, tunnel, session_id);
|
||||
session = l2tp_session_get(tunnel->l2tp_net, tunnel, session_id, true);
|
||||
if (!session || !session->recv_skb) {
|
||||
if (session) {
|
||||
if (session->deref)
|
||||
session->deref(session);
|
||||
l2tp_session_dec_refcount(session);
|
||||
}
|
||||
|
||||
/* Not found? Pass to userspace to deal with */
|
||||
l2tp_info(tunnel, L2TP_MSG_DATA,
|
||||
"%s: no session found (%u/%u). Passing up.\n",
|
||||
@@ -935,6 +1023,7 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
|
||||
goto error;
|
||||
|
||||
l2tp_recv_common(session, skb, ptr, optr, hdrflags, length, payload_hook);
|
||||
l2tp_session_dec_refcount(session);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1262,6 +1351,9 @@ again:
|
||||
|
||||
hlist_del_init(&session->hlist);
|
||||
|
||||
if (test_and_set_bit(0, &session->dead))
|
||||
goto again;
|
||||
|
||||
if (session->ref != NULL)
|
||||
(*session->ref)(session);
|
||||
|
||||
@@ -1710,6 +1802,9 @@ EXPORT_SYMBOL_GPL(__l2tp_session_unhash);
|
||||
*/
|
||||
int l2tp_session_delete(struct l2tp_session *session)
|
||||
{
|
||||
if (test_and_set_bit(0, &session->dead))
|
||||
return 0;
|
||||
|
||||
if (session->ref)
|
||||
(*session->ref)(session);
|
||||
__l2tp_session_unhash(session);
|
||||
@@ -1745,6 +1840,7 @@ EXPORT_SYMBOL_GPL(l2tp_session_set_header_len);
|
||||
struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg)
|
||||
{
|
||||
struct l2tp_session *session;
|
||||
int err;
|
||||
|
||||
session = kzalloc(sizeof(struct l2tp_session) + priv_size, GFP_KERNEL);
|
||||
if (session != NULL) {
|
||||
@@ -1800,6 +1896,13 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn
|
||||
|
||||
l2tp_session_set_header_len(session, tunnel->version);
|
||||
|
||||
err = l2tp_session_add_to_tunnel(tunnel, session);
|
||||
if (err) {
|
||||
kfree(session);
|
||||
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
/* Bump the reference count. The session context is deleted
|
||||
* only when this drops to zero.
|
||||
*/
|
||||
@@ -1809,28 +1912,14 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn
|
||||
/* Ensure tunnel socket isn't deleted */
|
||||
sock_hold(tunnel->sock);
|
||||
|
||||
/* Add session to the tunnel's hash list */
|
||||
write_lock_bh(&tunnel->hlist_lock);
|
||||
hlist_add_head(&session->hlist,
|
||||
l2tp_session_id_hash(tunnel, session_id));
|
||||
write_unlock_bh(&tunnel->hlist_lock);
|
||||
|
||||
/* And to the global session list if L2TPv3 */
|
||||
if (tunnel->version != L2TP_HDR_VER_2) {
|
||||
struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
|
||||
|
||||
spin_lock_bh(&pn->l2tp_session_hlist_lock);
|
||||
hlist_add_head_rcu(&session->global_hlist,
|
||||
l2tp_session_id_hash_2(pn, session_id));
|
||||
spin_unlock_bh(&pn->l2tp_session_hlist_lock);
|
||||
}
|
||||
|
||||
/* Ignore management session in session count value */
|
||||
if (session->session_id != 0)
|
||||
atomic_inc(&l2tp_session_count);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
return session;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2tp_session_create);
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ struct l2tp_session_cfg {
|
||||
struct l2tp_session {
|
||||
int magic; /* should be
|
||||
* L2TP_SESSION_MAGIC */
|
||||
long dead;
|
||||
|
||||
struct l2tp_tunnel *tunnel; /* back pointer to tunnel
|
||||
* context */
|
||||
@@ -243,6 +244,9 @@ out:
|
||||
return tunnel;
|
||||
}
|
||||
|
||||
struct l2tp_session *l2tp_session_get(struct net *net,
|
||||
struct l2tp_tunnel *tunnel,
|
||||
u32 session_id, bool do_ref);
|
||||
struct l2tp_session *l2tp_session_find(struct net *net,
|
||||
struct l2tp_tunnel *tunnel,
|
||||
u32 session_id);
|
||||
|
||||
@@ -223,12 +223,6 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p
|
||||
goto out;
|
||||
}
|
||||
|
||||
session = l2tp_session_find(net, tunnel, session_id);
|
||||
if (session) {
|
||||
rc = -EEXIST;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (cfg->ifname) {
|
||||
dev = dev_get_by_name(net, cfg->ifname);
|
||||
if (dev) {
|
||||
@@ -242,8 +236,8 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p
|
||||
|
||||
session = l2tp_session_create(sizeof(*spriv), tunnel, session_id,
|
||||
peer_session_id, cfg);
|
||||
if (!session) {
|
||||
rc = -ENOMEM;
|
||||
if (IS_ERR(session)) {
|
||||
rc = PTR_ERR(session);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
@@ -142,19 +142,19 @@ static int l2tp_ip_recv(struct sk_buff *skb)
|
||||
}
|
||||
|
||||
/* Ok, this is a data packet. Lookup the session. */
|
||||
session = l2tp_session_find(net, NULL, session_id);
|
||||
if (session == NULL)
|
||||
session = l2tp_session_get(net, NULL, session_id, true);
|
||||
if (!session)
|
||||
goto discard;
|
||||
|
||||
tunnel = session->tunnel;
|
||||
if (tunnel == NULL)
|
||||
goto discard;
|
||||
if (!tunnel)
|
||||
goto discard_sess;
|
||||
|
||||
/* Trace packet contents, if enabled */
|
||||
if (tunnel->debug & L2TP_MSG_DATA) {
|
||||
length = min(32u, skb->len);
|
||||
if (!pskb_may_pull(skb, length))
|
||||
goto discard;
|
||||
goto discard_sess;
|
||||
|
||||
/* Point to L2TP header */
|
||||
optr = ptr = skb->data;
|
||||
@@ -167,6 +167,7 @@ static int l2tp_ip_recv(struct sk_buff *skb)
|
||||
goto discard;
|
||||
|
||||
l2tp_recv_common(session, skb, ptr, optr, 0, skb->len, tunnel->recv_payload_hook);
|
||||
l2tp_session_dec_refcount(session);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -204,6 +205,12 @@ pass_up:
|
||||
|
||||
return sk_receive_skb(sk, skb, 1);
|
||||
|
||||
discard_sess:
|
||||
if (session->deref)
|
||||
session->deref(session);
|
||||
l2tp_session_dec_refcount(session);
|
||||
goto discard;
|
||||
|
||||
discard_put:
|
||||
sock_put(sk);
|
||||
|
||||
|
||||
@@ -127,6 +127,7 @@ static inline struct sock *l2tp_ip6_bind_lookup(struct net *net,
|
||||
*/
|
||||
static int l2tp_ip6_recv(struct sk_buff *skb)
|
||||
{
|
||||
struct net *net = dev_net(skb->dev);
|
||||
struct sock *sk;
|
||||
u32 session_id;
|
||||
u32 tunnel_id;
|
||||
@@ -153,19 +154,19 @@ static int l2tp_ip6_recv(struct sk_buff *skb)
|
||||
}
|
||||
|
||||
/* Ok, this is a data packet. Lookup the session. */
|
||||
session = l2tp_session_find(&init_net, NULL, session_id);
|
||||
if (session == NULL)
|
||||
session = l2tp_session_get(net, NULL, session_id, true);
|
||||
if (!session)
|
||||
goto discard;
|
||||
|
||||
tunnel = session->tunnel;
|
||||
if (tunnel == NULL)
|
||||
goto discard;
|
||||
if (!tunnel)
|
||||
goto discard_sess;
|
||||
|
||||
/* Trace packet contents, if enabled */
|
||||
if (tunnel->debug & L2TP_MSG_DATA) {
|
||||
length = min(32u, skb->len);
|
||||
if (!pskb_may_pull(skb, length))
|
||||
goto discard;
|
||||
goto discard_sess;
|
||||
|
||||
/* Point to L2TP header */
|
||||
optr = ptr = skb->data;
|
||||
@@ -179,6 +180,8 @@ static int l2tp_ip6_recv(struct sk_buff *skb)
|
||||
|
||||
l2tp_recv_common(session, skb, ptr, optr, 0, skb->len,
|
||||
tunnel->recv_payload_hook);
|
||||
l2tp_session_dec_refcount(session);
|
||||
|
||||
return 0;
|
||||
|
||||
pass_up:
|
||||
@@ -190,7 +193,7 @@ pass_up:
|
||||
goto discard;
|
||||
|
||||
tunnel_id = ntohl(*(__be32 *) &skb->data[4]);
|
||||
tunnel = l2tp_tunnel_find(&init_net, tunnel_id);
|
||||
tunnel = l2tp_tunnel_find(net, tunnel_id);
|
||||
if (tunnel) {
|
||||
sk = tunnel->sock;
|
||||
sock_hold(sk);
|
||||
@@ -198,7 +201,7 @@ pass_up:
|
||||
struct ipv6hdr *iph = ipv6_hdr(skb);
|
||||
|
||||
read_lock_bh(&l2tp_ip6_lock);
|
||||
sk = __l2tp_ip6_bind_lookup(&init_net, &iph->daddr,
|
||||
sk = __l2tp_ip6_bind_lookup(net, &iph->daddr,
|
||||
0, tunnel_id);
|
||||
if (!sk) {
|
||||
read_unlock_bh(&l2tp_ip6_lock);
|
||||
@@ -216,6 +219,12 @@ pass_up:
|
||||
|
||||
return sk_receive_skb(sk, skb, 1);
|
||||
|
||||
discard_sess:
|
||||
if (session->deref)
|
||||
session->deref(session);
|
||||
l2tp_session_dec_refcount(session);
|
||||
goto discard;
|
||||
|
||||
discard_put:
|
||||
sock_put(sk);
|
||||
|
||||
@@ -267,6 +276,7 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
||||
struct inet_sock *inet = inet_sk(sk);
|
||||
struct ipv6_pinfo *np = inet6_sk(sk);
|
||||
struct sockaddr_l2tpip6 *addr = (struct sockaddr_l2tpip6 *) uaddr;
|
||||
struct net *net = sock_net(sk);
|
||||
__be32 v4addr = 0;
|
||||
int addr_type;
|
||||
int err;
|
||||
@@ -288,7 +298,7 @@ static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
|
||||
|
||||
err = -EADDRINUSE;
|
||||
read_lock_bh(&l2tp_ip6_lock);
|
||||
if (__l2tp_ip6_bind_lookup(&init_net, &addr->l2tp_addr,
|
||||
if (__l2tp_ip6_bind_lookup(net, &addr->l2tp_addr,
|
||||
sk->sk_bound_dev_if, addr->l2tp_conn_id))
|
||||
goto out_in_use;
|
||||
read_unlock_bh(&l2tp_ip6_lock);
|
||||
@@ -461,7 +471,7 @@ static int l2tp_ip6_backlog_recv(struct sock *sk, struct sk_buff *skb)
|
||||
return 0;
|
||||
|
||||
drop:
|
||||
IP_INC_STATS(&init_net, IPSTATS_MIB_INDISCARDS);
|
||||
IP_INC_STATS(sock_net(sk), IPSTATS_MIB_INDISCARDS);
|
||||
kfree_skb(skb);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ static int pppol2tp_recv_payload_hook(struct sk_buff *skb)
|
||||
if (!pskb_may_pull(skb, 2))
|
||||
return 1;
|
||||
|
||||
if ((skb->data[0] == 0xff) && (skb->data[1] == 0x03))
|
||||
if ((skb->data[0] == PPP_ALLSTATIONS) && (skb->data[1] == PPP_UI))
|
||||
skb_pull(skb, 2);
|
||||
|
||||
return 0;
|
||||
@@ -297,7 +297,6 @@ static void pppol2tp_session_sock_put(struct l2tp_session *session)
|
||||
static int pppol2tp_sendmsg(struct socket *sock, struct msghdr *m,
|
||||
size_t total_len)
|
||||
{
|
||||
static const unsigned char ppph[2] = { 0xff, 0x03 };
|
||||
struct sock *sk = sock->sk;
|
||||
struct sk_buff *skb;
|
||||
int error;
|
||||
@@ -327,7 +326,7 @@ static int pppol2tp_sendmsg(struct socket *sock, struct msghdr *m,
|
||||
error = -ENOMEM;
|
||||
skb = sock_wmalloc(sk, NET_SKB_PAD + sizeof(struct iphdr) +
|
||||
uhlen + session->hdr_len +
|
||||
sizeof(ppph) + total_len,
|
||||
2 + total_len, /* 2 bytes for PPP_ALLSTATIONS & PPP_UI */
|
||||
0, GFP_KERNEL);
|
||||
if (!skb)
|
||||
goto error_put_sess_tun;
|
||||
@@ -340,8 +339,8 @@ static int pppol2tp_sendmsg(struct socket *sock, struct msghdr *m,
|
||||
skb_reserve(skb, uhlen);
|
||||
|
||||
/* Add PPP header */
|
||||
skb->data[0] = ppph[0];
|
||||
skb->data[1] = ppph[1];
|
||||
skb->data[0] = PPP_ALLSTATIONS;
|
||||
skb->data[1] = PPP_UI;
|
||||
skb_put(skb, 2);
|
||||
|
||||
/* Copy user data into skb */
|
||||
@@ -384,7 +383,6 @@ error:
|
||||
*/
|
||||
static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
|
||||
{
|
||||
static const u8 ppph[2] = { 0xff, 0x03 };
|
||||
struct sock *sk = (struct sock *) chan->private;
|
||||
struct sock *sk_tun;
|
||||
struct l2tp_session *session;
|
||||
@@ -413,14 +411,14 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
|
||||
sizeof(struct iphdr) + /* IP header */
|
||||
uhlen + /* UDP header (if L2TP_ENCAPTYPE_UDP) */
|
||||
session->hdr_len + /* L2TP header */
|
||||
sizeof(ppph); /* PPP header */
|
||||
2; /* 2 bytes for PPP_ALLSTATIONS & PPP_UI */
|
||||
if (skb_cow_head(skb, headroom))
|
||||
goto abort_put_sess_tun;
|
||||
|
||||
/* Setup PPP header */
|
||||
__skb_push(skb, sizeof(ppph));
|
||||
skb->data[0] = ppph[0];
|
||||
skb->data[1] = ppph[1];
|
||||
__skb_push(skb, 2);
|
||||
skb->data[0] = PPP_ALLSTATIONS;
|
||||
skb->data[1] = PPP_UI;
|
||||
|
||||
local_bh_disable();
|
||||
l2tp_xmit_skb(session, skb, session->hdr_len);
|
||||
@@ -454,11 +452,11 @@ static void pppol2tp_session_close(struct l2tp_session *session)
|
||||
|
||||
BUG_ON(session->magic != L2TP_SESSION_MAGIC);
|
||||
|
||||
if (sock) {
|
||||
inet_shutdown(sock, 2);
|
||||
/* Don't let the session go away before our socket does */
|
||||
l2tp_session_inc_refcount(session);
|
||||
}
|
||||
if (sock)
|
||||
inet_shutdown(sock, SEND_SHUTDOWN);
|
||||
|
||||
/* Don't let the session go away before our socket does */
|
||||
l2tp_session_inc_refcount(session);
|
||||
}
|
||||
|
||||
/* Really kill the session socket. (Called from sock_put() if
|
||||
@@ -600,6 +598,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
|
||||
int error = 0;
|
||||
u32 tunnel_id, peer_tunnel_id;
|
||||
u32 session_id, peer_session_id;
|
||||
bool drop_refcnt = false;
|
||||
int ver = 2;
|
||||
int fd;
|
||||
|
||||
@@ -708,36 +707,36 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
|
||||
if (tunnel->peer_tunnel_id == 0)
|
||||
tunnel->peer_tunnel_id = peer_tunnel_id;
|
||||
|
||||
/* Create session if it doesn't already exist. We handle the
|
||||
* case where a session was previously created by the netlink
|
||||
* interface by checking that the session doesn't already have
|
||||
* a socket and its tunnel socket are what we expect. If any
|
||||
* of those checks fail, return EEXIST to the caller.
|
||||
*/
|
||||
session = l2tp_session_find(sock_net(sk), tunnel, session_id);
|
||||
if (session == NULL) {
|
||||
/* Default MTU must allow space for UDP/L2TP/PPP
|
||||
* headers.
|
||||
*/
|
||||
cfg.mtu = cfg.mru = 1500 - PPPOL2TP_HEADER_OVERHEAD;
|
||||
session = l2tp_session_get(sock_net(sk), tunnel, session_id, false);
|
||||
if (session) {
|
||||
drop_refcnt = true;
|
||||
ps = l2tp_session_priv(session);
|
||||
|
||||
/* Allocate and initialize a new session context. */
|
||||
session = l2tp_session_create(sizeof(struct pppol2tp_session),
|
||||
tunnel, session_id,
|
||||
peer_session_id, &cfg);
|
||||
if (session == NULL) {
|
||||
error = -ENOMEM;
|
||||
/* Using a pre-existing session is fine as long as it hasn't
|
||||
* been connected yet.
|
||||
*/
|
||||
if (ps->sock) {
|
||||
error = -EEXIST;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* consistency checks */
|
||||
if (ps->tunnel_sock != tunnel->sock) {
|
||||
error = -EEXIST;
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
ps = l2tp_session_priv(session);
|
||||
error = -EEXIST;
|
||||
if (ps->sock != NULL)
|
||||
goto end;
|
||||
/* Default MTU must allow space for UDP/L2TP/PPP headers */
|
||||
cfg.mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD;
|
||||
cfg.mru = cfg.mtu;
|
||||
|
||||
/* consistency checks */
|
||||
if (ps->tunnel_sock != tunnel->sock)
|
||||
session = l2tp_session_create(sizeof(struct pppol2tp_session),
|
||||
tunnel, session_id,
|
||||
peer_session_id, &cfg);
|
||||
if (IS_ERR(session)) {
|
||||
error = PTR_ERR(session);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
/* Associate session with its PPPoL2TP socket */
|
||||
@@ -802,6 +801,8 @@ out_no_ppp:
|
||||
session->name);
|
||||
|
||||
end:
|
||||
if (drop_refcnt)
|
||||
l2tp_session_dec_refcount(session);
|
||||
release_sock(sk);
|
||||
|
||||
return error;
|
||||
@@ -829,12 +830,6 @@ static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_i
|
||||
if (tunnel->sock == NULL)
|
||||
goto out;
|
||||
|
||||
/* Check that this session doesn't already exist */
|
||||
error = -EEXIST;
|
||||
session = l2tp_session_find(net, tunnel, session_id);
|
||||
if (session != NULL)
|
||||
goto out;
|
||||
|
||||
/* Default MTU values. */
|
||||
if (cfg->mtu == 0)
|
||||
cfg->mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD;
|
||||
@@ -842,12 +837,13 @@ static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_i
|
||||
cfg->mru = cfg->mtu;
|
||||
|
||||
/* Allocate and initialize a new session context. */
|
||||
error = -ENOMEM;
|
||||
session = l2tp_session_create(sizeof(struct pppol2tp_session),
|
||||
tunnel, session_id,
|
||||
peer_session_id, cfg);
|
||||
if (session == NULL)
|
||||
if (IS_ERR(session)) {
|
||||
error = PTR_ERR(session);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ps = l2tp_session_priv(session);
|
||||
ps->tunnel_sock = tunnel->sock;
|
||||
@@ -889,10 +885,8 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,
|
||||
|
||||
pls = l2tp_session_priv(session);
|
||||
tunnel = l2tp_sock_to_tunnel(pls->tunnel_sock);
|
||||
if (tunnel == NULL) {
|
||||
error = -EBADF;
|
||||
if (tunnel == NULL)
|
||||
goto end_put_sess;
|
||||
}
|
||||
|
||||
inet = inet_sk(tunnel->sock);
|
||||
if ((tunnel->version == 2) && (tunnel->sock->sk_family == AF_INET)) {
|
||||
@@ -970,12 +964,11 @@ static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,
|
||||
}
|
||||
|
||||
*usockaddr_len = len;
|
||||
error = 0;
|
||||
|
||||
sock_put(pls->tunnel_sock);
|
||||
end_put_sess:
|
||||
sock_put(sk);
|
||||
error = 0;
|
||||
|
||||
end:
|
||||
return error;
|
||||
}
|
||||
@@ -1171,11 +1164,18 @@ static int pppol2tp_tunnel_ioctl(struct l2tp_tunnel *tunnel,
|
||||
if (stats.session_id != 0) {
|
||||
/* resend to session ioctl handler */
|
||||
struct l2tp_session *session =
|
||||
l2tp_session_find(sock_net(sk), tunnel, stats.session_id);
|
||||
if (session != NULL)
|
||||
err = pppol2tp_session_ioctl(session, cmd, arg);
|
||||
else
|
||||
l2tp_session_get(sock_net(sk), tunnel,
|
||||
stats.session_id, true);
|
||||
|
||||
if (session) {
|
||||
err = pppol2tp_session_ioctl(session, cmd,
|
||||
arg);
|
||||
if (session->deref)
|
||||
session->deref(session);
|
||||
l2tp_session_dec_refcount(session);
|
||||
} else {
|
||||
err = -EBADR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifdef CONFIG_XFRM
|
||||
|
||||
@@ -234,7 +234,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
|
||||
{
|
||||
struct sctp_association *asoc = t->asoc;
|
||||
struct dst_entry *dst = NULL;
|
||||
struct flowi6 *fl6 = &fl->u.ip6;
|
||||
struct flowi _fl;
|
||||
struct flowi6 *fl6 = &_fl.u.ip6;
|
||||
struct sctp_bind_addr *bp;
|
||||
struct ipv6_pinfo *np = inet6_sk(sk);
|
||||
struct sctp_sockaddr_entry *laddr;
|
||||
@@ -244,7 +245,7 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
|
||||
__u8 matchlen = 0;
|
||||
sctp_scope_t scope;
|
||||
|
||||
memset(fl6, 0, sizeof(struct flowi6));
|
||||
memset(&_fl, 0, sizeof(_fl));
|
||||
fl6->daddr = daddr->v6.sin6_addr;
|
||||
fl6->fl6_dport = daddr->v6.sin6_port;
|
||||
fl6->flowi6_proto = IPPROTO_SCTP;
|
||||
@@ -268,8 +269,11 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
|
||||
rcu_read_unlock();
|
||||
|
||||
dst = ip6_dst_lookup_flow(sk, fl6, final_p);
|
||||
if (!asoc || saddr)
|
||||
if (!asoc || saddr) {
|
||||
t->dst = dst;
|
||||
memcpy(fl, &_fl, sizeof(_fl));
|
||||
goto out;
|
||||
}
|
||||
|
||||
bp = &asoc->base.bind_addr;
|
||||
scope = sctp_scope(daddr);
|
||||
@@ -292,6 +296,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
|
||||
if ((laddr->a.sa.sa_family == AF_INET6) &&
|
||||
(sctp_v6_cmp_addr(&dst_saddr, &laddr->a))) {
|
||||
rcu_read_unlock();
|
||||
t->dst = dst;
|
||||
memcpy(fl, &_fl, sizeof(_fl));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -330,6 +336,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
|
||||
if (!IS_ERR_OR_NULL(dst))
|
||||
dst_release(dst);
|
||||
dst = bdst;
|
||||
t->dst = dst;
|
||||
memcpy(fl, &_fl, sizeof(_fl));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -343,6 +351,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
|
||||
dst_release(dst);
|
||||
dst = bdst;
|
||||
matchlen = bmatchlen;
|
||||
t->dst = dst;
|
||||
memcpy(fl, &_fl, sizeof(_fl));
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
@@ -351,14 +361,12 @@ out:
|
||||
struct rt6_info *rt;
|
||||
|
||||
rt = (struct rt6_info *)dst;
|
||||
t->dst = dst;
|
||||
t->dst_cookie = rt6_get_cookie(rt);
|
||||
pr_debug("rt6_dst:%pI6/%d rt6_src:%pI6\n",
|
||||
&rt->rt6i_dst.addr, rt->rt6i_dst.plen,
|
||||
&fl6->saddr);
|
||||
&fl->u.ip6.saddr);
|
||||
} else {
|
||||
t->dst = NULL;
|
||||
|
||||
pr_debug("no route\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,14 +428,15 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
|
||||
{
|
||||
struct sctp_association *asoc = t->asoc;
|
||||
struct rtable *rt;
|
||||
struct flowi4 *fl4 = &fl->u.ip4;
|
||||
struct flowi _fl;
|
||||
struct flowi4 *fl4 = &_fl.u.ip4;
|
||||
struct sctp_bind_addr *bp;
|
||||
struct sctp_sockaddr_entry *laddr;
|
||||
struct dst_entry *dst = NULL;
|
||||
union sctp_addr *daddr = &t->ipaddr;
|
||||
union sctp_addr dst_saddr;
|
||||
|
||||
memset(fl4, 0x0, sizeof(struct flowi4));
|
||||
memset(&_fl, 0x0, sizeof(_fl));
|
||||
fl4->daddr = daddr->v4.sin_addr.s_addr;
|
||||
fl4->fl4_dport = daddr->v4.sin_port;
|
||||
fl4->flowi4_proto = IPPROTO_SCTP;
|
||||
@@ -453,8 +454,11 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
|
||||
&fl4->saddr);
|
||||
|
||||
rt = ip_route_output_key(sock_net(sk), fl4);
|
||||
if (!IS_ERR(rt))
|
||||
if (!IS_ERR(rt)) {
|
||||
dst = &rt->dst;
|
||||
t->dst = dst;
|
||||
memcpy(fl, &_fl, sizeof(_fl));
|
||||
}
|
||||
|
||||
/* If there is no association or if a source address is passed, no
|
||||
* more validation is required.
|
||||
@@ -517,27 +521,33 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
|
||||
odev = __ip_dev_find(sock_net(sk), laddr->a.v4.sin_addr.s_addr,
|
||||
false);
|
||||
if (!odev || odev->ifindex != fl4->flowi4_oif) {
|
||||
if (!dst)
|
||||
if (!dst) {
|
||||
dst = &rt->dst;
|
||||
else
|
||||
t->dst = dst;
|
||||
memcpy(fl, &_fl, sizeof(_fl));
|
||||
} else {
|
||||
dst_release(&rt->dst);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
dst_release(dst);
|
||||
dst = &rt->dst;
|
||||
t->dst = dst;
|
||||
memcpy(fl, &_fl, sizeof(_fl));
|
||||
break;
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
rcu_read_unlock();
|
||||
out:
|
||||
t->dst = dst;
|
||||
if (dst)
|
||||
if (dst) {
|
||||
pr_debug("rt_dst:%pI4, rt_src:%pI4\n",
|
||||
&fl4->daddr, &fl4->saddr);
|
||||
else
|
||||
&fl->u.ip4.daddr, &fl->u.ip4.saddr);
|
||||
} else {
|
||||
t->dst = NULL;
|
||||
pr_debug("no route\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* For v4, the source address is cached in the route entry(dst). So no need
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
#define JZ_AIC_I2S_STATUS_BUSY BIT(2)
|
||||
|
||||
#define JZ_AIC_CLK_DIV_MASK 0xf
|
||||
#define I2SDIV_DV_SHIFT 8
|
||||
#define I2SDIV_DV_SHIFT 0
|
||||
#define I2SDIV_DV_MASK (0xf << I2SDIV_DV_SHIFT)
|
||||
#define I2SDIV_IDV_SHIFT 8
|
||||
#define I2SDIV_IDV_MASK (0xf << I2SDIV_IDV_SHIFT)
|
||||
|
||||
Reference in New Issue
Block a user