From 10ebd8556b7990499c896a550e3d416b444211e6 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Fri, 10 May 2024 02:23:07 +0000
Subject: [PATCH] add led
---
kernel/drivers/net/ppp/ppp_generic.c | 264 ++++++++++++++++++++++++++++++++++------------------
1 files changed, 172 insertions(+), 92 deletions(-)
diff --git a/kernel/drivers/net/ppp/ppp_generic.c b/kernel/drivers/net/ppp/ppp_generic.c
index 61de03c..b825c6a 100644
--- a/kernel/drivers/net/ppp/ppp_generic.c
+++ b/kernel/drivers/net/ppp/ppp_generic.c
@@ -1,12 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Generic PPP layer for Linux.
*
* Copyright 1999-2002 Paul Mackerras.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
*
* The generic PPP layer handles the PPP network interfaces, the
* /dev/ppp device, packet and VJ compression, and multilink.
@@ -276,7 +272,7 @@
static struct sk_buff *ppp_mp_reconstruct(struct ppp *ppp);
static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb);
#endif /* CONFIG_PPP_MULTILINK */
-static int ppp_set_compress(struct ppp *ppp, unsigned long arg);
+static int ppp_set_compress(struct ppp *ppp, struct ppp_option_data *data);
static void ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound);
static void ppp_ccp_closed(struct ppp *ppp);
static struct compressor *find_compressor(int type);
@@ -302,8 +298,6 @@
/* per net-namespace data */
static inline struct ppp_net *ppp_pernet(struct net *net)
{
- BUG_ON(!net);
-
return net_generic(net, ppp_net_id);
}
@@ -563,36 +557,67 @@
}
#ifdef CONFIG_PPP_FILTER
-static int get_filter(void __user *arg, struct sock_filter **p)
+static struct bpf_prog *get_filter(struct sock_fprog *uprog)
+{
+ struct sock_fprog_kern fprog;
+ struct bpf_prog *res = NULL;
+ int err;
+
+ if (!uprog->len)
+ return NULL;
+
+ /* uprog->len is unsigned short, so no overflow here */
+ fprog.len = uprog->len;
+ fprog.filter = memdup_user(uprog->filter,
+ uprog->len * sizeof(struct sock_filter));
+ if (IS_ERR(fprog.filter))
+ return ERR_CAST(fprog.filter);
+
+ err = bpf_prog_create(&res, &fprog);
+ kfree(fprog.filter);
+
+ return err ? ERR_PTR(err) : res;
+}
+
+static struct bpf_prog *ppp_get_filter(struct sock_fprog __user *p)
{
struct sock_fprog uprog;
- struct sock_filter *code = NULL;
- int len;
- if (copy_from_user(&uprog, arg, sizeof(uprog)))
- return -EFAULT;
-
- if (!uprog.len) {
- *p = NULL;
- return 0;
- }
-
- len = uprog.len * sizeof(struct sock_filter);
- code = memdup_user(uprog.filter, len);
- if (IS_ERR(code))
- return PTR_ERR(code);
-
- *p = code;
- return uprog.len;
+ if (copy_from_user(&uprog, p, sizeof(struct sock_fprog)))
+ return ERR_PTR(-EFAULT);
+ return get_filter(&uprog);
}
-#endif /* CONFIG_PPP_FILTER */
+
+#ifdef CONFIG_COMPAT
+struct sock_fprog32 {
+ unsigned short len;
+ compat_caddr_t filter;
+};
+
+#define PPPIOCSPASS32 _IOW('t', 71, struct sock_fprog32)
+#define PPPIOCSACTIVE32 _IOW('t', 70, struct sock_fprog32)
+
+static struct bpf_prog *compat_ppp_get_filter(struct sock_fprog32 __user *p)
+{
+ struct sock_fprog32 uprog32;
+ struct sock_fprog uprog;
+
+ if (copy_from_user(&uprog32, p, sizeof(struct sock_fprog32)))
+ return ERR_PTR(-EFAULT);
+ uprog.len = uprog32.len;
+ uprog.filter = compat_ptr(uprog32.filter);
+ return get_filter(&uprog);
+}
+#endif
+#endif
static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct ppp_file *pf;
struct ppp *ppp;
int err = -EFAULT, val, val2, i;
- struct ppp_idle idle;
+ struct ppp_idle32 idle32;
+ struct ppp_idle64 idle64;
struct npioctl npi;
int unit, cflags;
struct slcompress *vj;
@@ -688,9 +713,14 @@
break;
case PPPIOCSCOMPRESS:
- err = ppp_set_compress(ppp, arg);
+ {
+ struct ppp_option_data data;
+ if (copy_from_user(&data, argp, sizeof(data)))
+ err = -EFAULT;
+ else
+ err = ppp_set_compress(ppp, &data);
break;
-
+ }
case PPPIOCGUNIT:
if (put_user(ppp->file.index, p))
break;
@@ -710,10 +740,18 @@
err = 0;
break;
- case PPPIOCGIDLE:
- idle.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
- idle.recv_idle = (jiffies - ppp->last_recv) / HZ;
- if (copy_to_user(argp, &idle, sizeof(idle)))
+ case PPPIOCGIDLE32:
+ idle32.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
+ idle32.recv_idle = (jiffies - ppp->last_recv) / HZ;
+ if (copy_to_user(argp, &idle32, sizeof(idle32)))
+ break;
+ err = 0;
+ break;
+
+ case PPPIOCGIDLE64:
+ idle64.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
+ idle64.recv_idle = (jiffies - ppp->last_recv) / HZ;
+ if (copy_to_user(argp, &idle64, sizeof(idle64)))
break;
err = 0;
break;
@@ -762,55 +800,25 @@
#ifdef CONFIG_PPP_FILTER
case PPPIOCSPASS:
- {
- struct sock_filter *code;
-
- err = get_filter(argp, &code);
- if (err >= 0) {
- struct bpf_prog *pass_filter = NULL;
- struct sock_fprog_kern fprog = {
- .len = err,
- .filter = code,
- };
-
- err = 0;
- if (fprog.filter)
- err = bpf_prog_create(&pass_filter, &fprog);
- if (!err) {
- ppp_lock(ppp);
- if (ppp->pass_filter)
- bpf_prog_destroy(ppp->pass_filter);
- ppp->pass_filter = pass_filter;
- ppp_unlock(ppp);
- }
- kfree(code);
- }
- break;
- }
case PPPIOCSACTIVE:
{
- struct sock_filter *code;
+ struct bpf_prog *filter = ppp_get_filter(argp);
+ struct bpf_prog **which;
- err = get_filter(argp, &code);
- if (err >= 0) {
- struct bpf_prog *active_filter = NULL;
- struct sock_fprog_kern fprog = {
- .len = err,
- .filter = code,
- };
-
- err = 0;
- if (fprog.filter)
- err = bpf_prog_create(&active_filter, &fprog);
- if (!err) {
- ppp_lock(ppp);
- if (ppp->active_filter)
- bpf_prog_destroy(ppp->active_filter);
- ppp->active_filter = active_filter;
- ppp_unlock(ppp);
- }
- kfree(code);
+ if (IS_ERR(filter)) {
+ err = PTR_ERR(filter);
+ break;
}
+ if (cmd == PPPIOCSPASS)
+ which = &ppp->pass_filter;
+ else
+ which = &ppp->active_filter;
+ ppp_lock(ppp);
+ if (*which)
+ bpf_prog_destroy(*which);
+ *which = filter;
+ ppp_unlock(ppp);
+ err = 0;
break;
}
#endif /* CONFIG_PPP_FILTER */
@@ -835,6 +843,77 @@
return err;
}
+
+#ifdef CONFIG_COMPAT
+struct ppp_option_data32 {
+ compat_uptr_t ptr;
+ u32 length;
+ compat_int_t transmit;
+};
+#define PPPIOCSCOMPRESS32 _IOW('t', 77, struct ppp_option_data32)
+
+static long ppp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct ppp_file *pf;
+ int err = -ENOIOCTLCMD;
+ void __user *argp = (void __user *)arg;
+
+ mutex_lock(&ppp_mutex);
+
+ pf = file->private_data;
+ if (pf && pf->kind == INTERFACE) {
+ struct ppp *ppp = PF_TO_PPP(pf);
+ switch (cmd) {
+#ifdef CONFIG_PPP_FILTER
+ case PPPIOCSPASS32:
+ case PPPIOCSACTIVE32:
+ {
+ struct bpf_prog *filter = compat_ppp_get_filter(argp);
+ struct bpf_prog **which;
+
+ if (IS_ERR(filter)) {
+ err = PTR_ERR(filter);
+ break;
+ }
+ if (cmd == PPPIOCSPASS32)
+ which = &ppp->pass_filter;
+ else
+ which = &ppp->active_filter;
+ ppp_lock(ppp);
+ if (*which)
+ bpf_prog_destroy(*which);
+ *which = filter;
+ ppp_unlock(ppp);
+ err = 0;
+ break;
+ }
+#endif /* CONFIG_PPP_FILTER */
+ case PPPIOCSCOMPRESS32:
+ {
+ struct ppp_option_data32 data32;
+ if (copy_from_user(&data32, argp, sizeof(data32))) {
+ err = -EFAULT;
+ } else {
+ struct ppp_option_data data = {
+ .ptr = compat_ptr(data32.ptr),
+ .length = data32.length,
+ .transmit = data32.transmit
+ };
+ err = ppp_set_compress(ppp, &data);
+ }
+ break;
+ }
+ }
+ }
+ mutex_unlock(&ppp_mutex);
+
+ /* all other commands have compatible arguments */
+ if (err == -ENOIOCTLCMD)
+ err = ppp_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+
+ return err;
+}
+#endif
static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
struct file *file, unsigned int cmd, unsigned long arg)
@@ -904,6 +983,9 @@
.write = ppp_write,
.poll = ppp_poll,
.unlocked_ioctl = ppp_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ppp_compat_ioctl,
+#endif
.open = ppp_open,
.release = ppp_release,
.llseek = noop_llseek,
@@ -1527,6 +1609,8 @@
struct sk_buff *new_skb;
int len;
unsigned char *cp;
+
+ skb->dev = ppp->dev;
if (proto < 0x8000) {
#ifdef CONFIG_PPP_FILTER
@@ -2466,7 +2550,7 @@
if (ppp->mrru == 0) /* do nothing until mrru is set */
return NULL;
- head = list->next;
+ head = __skb_peek(list);
tail = NULL;
skb_queue_walk_safe(list, p, tmp) {
again:
@@ -2756,24 +2840,20 @@
/* Process the PPPIOCSCOMPRESS ioctl. */
static int
-ppp_set_compress(struct ppp *ppp, unsigned long arg)
+ppp_set_compress(struct ppp *ppp, struct ppp_option_data *data)
{
- int err;
+ int err = -EFAULT;
struct compressor *cp, *ocomp;
- struct ppp_option_data data;
void *state, *ostate;
unsigned char ccp_option[CCP_MAX_OPTION_LENGTH];
- err = -EFAULT;
- if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
+ if (data->length > CCP_MAX_OPTION_LENGTH)
goto out;
- if (data.length > CCP_MAX_OPTION_LENGTH)
- goto out;
- if (copy_from_user(ccp_option, (void __user *) data.ptr, data.length))
+ if (copy_from_user(ccp_option, data->ptr, data->length))
goto out;
err = -EINVAL;
- if (data.length < 2 || ccp_option[1] < 2 || ccp_option[1] > data.length)
+ if (data->length < 2 || ccp_option[1] < 2 || ccp_option[1] > data->length)
goto out;
cp = try_then_request_module(
@@ -2783,8 +2863,8 @@
goto out;
err = -ENOBUFS;
- if (data.transmit) {
- state = cp->comp_alloc(ccp_option, data.length);
+ if (data->transmit) {
+ state = cp->comp_alloc(ccp_option, data->length);
if (state) {
ppp_xmit_lock(ppp);
ppp->xstate &= ~SC_COMP_RUN;
@@ -2802,7 +2882,7 @@
module_put(cp->owner);
} else {
- state = cp->decomp_alloc(ccp_option, data.length);
+ state = cp->decomp_alloc(ccp_option, data->length);
if (state) {
ppp_recv_lock(ppp);
ppp->rstate &= ~SC_DECOMP_RUN;
--
Gitblit v1.6.2