diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-22 10:56:23 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-22 10:56:23 -0800 |
commit | 36177ba655c238e33400cc2837a28720b62784bd (patch) | |
tree | c285738397f0272f1e0e973c5e6a53b2e8da74b1 | |
parent | 2152f8536668a957ea3214735b4761e7b22ef7d8 (diff) | |
parent | 056755f4d73d49b4adcbb8ecdaf75138cf166bd3 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6:
[TG3]: Bump driver version and reldate.
[TG3]: Skip phy power down on some devices
[TG3]: Fix SRAM access during tg3_init_one()
[X25]: dte facilities 32 64 ioctl conversion
[X25]: allow ITU-T DTE facilities for x25
[X25]: fix kernel error message 64 bit kernel
[X25]: ioctl conversion 32 bit user to 64 bit kernel
[NET]: socket timestamp 32 bit handler for 64 bit kernel
[NET]: allow 32 bit socket ioctl in 64 bit kernel
[BLUETOOTH]: Return negative error constant
-rw-r--r-- | drivers/net/tg3.c | 32 | ||||
-rw-r--r-- | include/linux/net.h | 6 | ||||
-rw-r--r-- | include/linux/x25.h | 26 | ||||
-rw-r--r-- | include/net/compat.h | 4 | ||||
-rw-r--r-- | include/net/x25.h | 21 | ||||
-rw-r--r-- | net/bluetooth/bnep/core.c | 4 | ||||
-rw-r--r-- | net/compat.c | 19 | ||||
-rw-r--r-- | net/socket.c | 21 | ||||
-rw-r--r-- | net/x25/af_x25.c | 173 | ||||
-rw-r--r-- | net/x25/x25_facilities.c | 82 | ||||
-rw-r--r-- | net/x25/x25_in.c | 3 | ||||
-rw-r--r-- | net/x25/x25_subr.c | 6 |
12 files changed, 366 insertions, 31 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e03d1ae50c3..88829eb9568 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -69,8 +69,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.52" -#define DRV_MODULE_RELDATE "Mar 06, 2006" +#define DRV_MODULE_VERSION "3.53" +#define DRV_MODULE_RELDATE "Mar 22, 2006" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -1148,6 +1148,19 @@ static int tg3_halt_cpu(struct tg3 *, u32); static int tg3_nvram_lock(struct tg3 *); static void tg3_nvram_unlock(struct tg3 *); +static void tg3_power_down_phy(struct tg3 *tp) +{ + /* The PHY should not be powered down on some chips because + * of bugs. + */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 && + (tp->tg3_flags2 & TG3_FLG2_MII_SERDES))) + return; + tg3_writephy(tp, MII_BMCR, BMCR_PDOWN); +} + static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) { u32 misc_host_ctrl; @@ -1327,8 +1340,7 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) tg3_writephy(tp, MII_TG3_EXT_CTRL, MII_TG3_EXT_CTRL_FORCE_LED_OFF); tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2); - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) - tg3_writephy(tp, MII_BMCR, BMCR_PDOWN); + tg3_power_down_phy(tp); } } @@ -9436,12 +9448,18 @@ static inline struct subsys_tbl_ent *lookup_by_subsys(struct tg3 *tp) return NULL; } -/* Since this function may be called in D3-hot power state during - * tg3_init_one(), only config cycles are allowed. - */ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) { u32 val; + u16 pmcsr; + + /* On some early chips the SRAM cannot be accessed in D3hot state, + * so need make sure we're in D0. + */ + pci_read_config_word(tp->pdev, tp->pm_cap + PCI_PM_CTRL, &pmcsr); + pmcsr &= ~PCI_PM_CTRL_STATE_MASK; + pci_write_config_word(tp->pdev, tp->pm_cap + PCI_PM_CTRL, pmcsr); + msleep(1); /* Make sure register accesses (indirect or otherwise) * will function correctly. diff --git a/include/linux/net.h b/include/linux/net.h index 152fa6551fd..84a490e5f0a 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -143,6 +143,8 @@ struct proto_ops { struct poll_table_struct *wait); int (*ioctl) (struct socket *sock, unsigned int cmd, unsigned long arg); + int (*compat_ioctl) (struct socket *sock, unsigned int cmd, + unsigned long arg); int (*listen) (struct socket *sock, int len); int (*shutdown) (struct socket *sock, int flags); int (*setsockopt)(struct socket *sock, int level, @@ -251,6 +253,8 @@ SOCKCALL_UWRAP(name, poll, (struct file *file, struct socket *sock, struct poll_ (file, sock, wait)) \ SOCKCALL_WRAP(name, ioctl, (struct socket *sock, unsigned int cmd, \ unsigned long arg), (sock, cmd, arg)) \ +SOCKCALL_WRAP(name, compat_ioctl, (struct socket *sock, unsigned int cmd, \ + unsigned long arg), (sock, cmd, arg)) \ SOCKCALL_WRAP(name, listen, (struct socket *sock, int len), (sock, len)) \ SOCKCALL_WRAP(name, shutdown, (struct socket *sock, int flags), (sock, flags)) \ SOCKCALL_WRAP(name, setsockopt, (struct socket *sock, int level, int optname, \ @@ -275,6 +279,7 @@ static const struct proto_ops name##_ops = { \ .getname = __lock_##name##_getname, \ .poll = __lock_##name##_poll, \ .ioctl = __lock_##name##_ioctl, \ + .compat_ioctl = __lock_##name##_compat_ioctl, \ .listen = __lock_##name##_listen, \ .shutdown = __lock_##name##_shutdown, \ .setsockopt = __lock_##name##_setsockopt, \ @@ -283,6 +288,7 @@ static const struct proto_ops name##_ops = { \ .recvmsg = __lock_##name##_recvmsg, \ .mmap = __lock_##name##_mmap, \ }; + #endif #define MODULE_ALIAS_NETPROTO(proto) \ diff --git a/include/linux/x25.h b/include/linux/x25.h index 16d44931afa..d035e4e87d0 100644 --- a/include/linux/x25.h +++ b/include/linux/x25.h @@ -11,6 +11,8 @@ #ifndef X25_KERNEL_H #define X25_KERNEL_H +#include <linux/types.h> + #define SIOCX25GSUBSCRIP (SIOCPROTOPRIVATE + 0) #define SIOCX25SSUBSCRIP (SIOCPROTOPRIVATE + 1) #define SIOCX25GFACILITIES (SIOCPROTOPRIVATE + 2) @@ -21,6 +23,8 @@ #define SIOCX25SCUDMATCHLEN (SIOCPROTOPRIVATE + 7) #define SIOCX25CALLACCPTAPPRV (SIOCPROTOPRIVATE + 8) #define SIOCX25SENDCALLACCPT (SIOCPROTOPRIVATE + 9) +#define SIOCX25GDTEFACILITIES (SIOCPROTOPRIVATE + 10) +#define SIOCX25SDTEFACILITIES (SIOCPROTOPRIVATE + 11) /* * Values for {get,set}sockopt. @@ -77,6 +81,8 @@ struct x25_subscrip_struct { #define X25_MASK_PACKET_SIZE 0x04 #define X25_MASK_WINDOW_SIZE 0x08 +#define X25_MASK_CALLING_AE 0x10 +#define X25_MASK_CALLED_AE 0x20 /* @@ -99,6 +105,26 @@ struct x25_facilities { }; /* +* ITU DTE facilities +* Only the called and calling address +* extension are currently implemented. +* The rest are in place to avoid the struct +* changing size if someone needs them later +*/ + +struct x25_dte_facilities { + __u16 delay_cumul; + __u16 delay_target; + __u16 delay_max; + __u8 min_throughput; + __u8 expedited; + __u8 calling_len; + __u8 called_len; + __u8 calling_ae[20]; + __u8 called_ae[20]; +}; + +/* * Call User Data structure. */ struct x25_calluserdata { diff --git a/include/net/compat.h b/include/net/compat.h index 290bab46d45..8662b8f43df 100644 --- a/include/net/compat.h +++ b/include/net/compat.h @@ -23,6 +23,9 @@ struct compat_cmsghdr { compat_int_t cmsg_type; }; +struct sock; +extern int compat_sock_get_timestamp(struct sock *, struct timeval __user *); + #else /* defined(CONFIG_COMPAT) */ #define compat_msghdr msghdr /* to avoid compiler warnings */ #endif /* defined(CONFIG_COMPAT) */ @@ -34,7 +37,6 @@ extern asmlinkage long compat_sys_recvmsg(int,struct compat_msghdr __user *,unsi extern asmlinkage long compat_sys_getsockopt(int, int, int, char __user *, int __user *); extern int put_cmsg_compat(struct msghdr*, int, int, int, void *); -struct sock; extern int cmsghdr_from_user_compat_to_kern(struct msghdr *, struct sock *, unsigned char *, int); #endif /* NET_COMPAT_H */ diff --git a/include/net/x25.h b/include/net/x25.h index fee62ff8c19..0ad90ebcf86 100644 --- a/include/net/x25.h +++ b/include/net/x25.h @@ -101,9 +101,17 @@ enum { #define X25_FAC_PACKET_SIZE 0x42 #define X25_FAC_WINDOW_SIZE 0x43 -#define X25_MAX_FAC_LEN 20 /* Plenty to spare */ +#define X25_MAX_FAC_LEN 60 #define X25_MAX_CUD_LEN 128 +#define X25_FAC_CALLING_AE 0xCB +#define X25_FAC_CALLED_AE 0xC9 + +#define X25_MARKER 0x00 +#define X25_DTE_SERVICES 0x0F +#define X25_MAX_AE_LEN 40 /* Max num of semi-octets in AE - OSI Nw */ +#define X25_MAX_DTE_FACIL_LEN 21 /* Max length of DTE facility params */ + /** * struct x25_route - x25 routing entry * @node - entry in x25_list_lock @@ -148,6 +156,7 @@ struct x25_sock { struct timer_list timer; struct x25_causediag causediag; struct x25_facilities facilities; + struct x25_dte_facilities dte_facilities; struct x25_calluserdata calluserdata; unsigned long vc_facil_mask; /* inc_call facilities mask */ }; @@ -180,9 +189,13 @@ extern void x25_establish_link(struct x25_neigh *); extern void x25_terminate_link(struct x25_neigh *); /* x25_facilities.c */ -extern int x25_parse_facilities(struct sk_buff *, struct x25_facilities *, unsigned long *); -extern int x25_create_facilities(unsigned char *, struct x25_facilities *, unsigned long); -extern int x25_negotiate_facilities(struct sk_buff *, struct sock *, struct x25_facilities *); +extern int x25_parse_facilities(struct sk_buff *, struct x25_facilities *, + struct x25_dte_facilities *, unsigned long *); +extern int x25_create_facilities(unsigned char *, struct x25_facilities *, + struct x25_dte_facilities *, unsigned long); +extern int x25_negotiate_facilities(struct sk_buff *, struct sock *, + struct x25_facilities *, + struct x25_dte_facilities *); extern void x25_limit_facilities(struct x25_facilities *, struct x25_neigh *); /* x25_in.c */ diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index cbb20c32a6c..d908d49dc9f 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -532,8 +532,8 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) dev = alloc_netdev(sizeof(struct bnep_session), (*req->device) ? req->device : "bnep%d", bnep_net_setup); - if (!dev) - return ENOMEM; + if (!dev) + return -ENOMEM; down_write(&bnep_session_sem); diff --git a/net/compat.c b/net/compat.c index 13177a1a4b3..8fd37cd7b50 100644 --- a/net/compat.c +++ b/net/compat.c @@ -543,6 +543,25 @@ static int compat_sock_getsockopt(struct socket *sock, int level, int optname, return sock_getsockopt(sock, level, optname, optval, optlen); } +int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp) +{ + struct compat_timeval __user *ctv = + (struct compat_timeval __user*) userstamp; + int err = -ENOENT; + + if (!sock_flag(sk, SOCK_TIMESTAMP)) + sock_enable_timestamp(sk); + if (sk->sk_stamp.tv_sec == -1) + return err; + if (sk->sk_stamp.tv_sec == 0) + do_gettimeofday(&sk->sk_stamp); + if (put_user(sk->sk_stamp.tv_sec, &ctv->tv_sec) || + put_user(sk->sk_stamp.tv_usec, &ctv->tv_usec)) + err = -EFAULT; + return err; +} +EXPORT_SYMBOL(compat_sock_get_timestamp); + asmlinkage long compat_sys_getsockopt(int fd, int level, int optname, char __user *optval, int __user *optlen) { diff --git a/net/socket.c b/net/socket.c index e3c21d5ec28..e2d5bae994d 100644 --- a/net/socket.c +++ b/net/socket.c @@ -107,6 +107,10 @@ static unsigned int sock_poll(struct file *file, struct poll_table_struct *wait); static long sock_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +#ifdef CONFIG_COMPAT +static long compat_sock_ioctl(struct file *file, + unsigned int cmd, unsigned long arg); +#endif static int sock_fasync(int fd, struct file *filp, int on); static ssize_t sock_readv(struct file *file, const struct iovec *vector, unsigned long count, loff_t *ppos); @@ -128,6 +132,9 @@ static struct file_operations socket_file_ops = { .aio_write = sock_aio_write, .poll = sock_poll, .unlocked_ioctl = sock_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = compat_sock_ioctl, +#endif .mmap = sock_mmap, .open = sock_no_open, /* special open code to disallow open via /proc */ .release = sock_close, @@ -2136,6 +2143,20 @@ void socket_seq_show(struct seq_file *seq) } #endif /* CONFIG_PROC_FS */ +#ifdef CONFIG_COMPAT +static long compat_sock_ioctl(struct file *file, unsigned cmd, + unsigned long arg) +{ + struct socket *sock = file->private_data; + int ret = -ENOIOCTLCMD; + + if (sock->ops->compat_ioctl) + ret = sock->ops->compat_ioctl(sock, cmd, arg); + + return ret; +} +#endif + /* ABI emulation layers need these two */ EXPORT_SYMBOL(move_addr_to_kernel); EXPORT_SYMBOL(move_addr_to_user); diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 72b6ff3299b..282ce4e40d7 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -54,7 +54,10 @@ #include <linux/termios.h> /* For TIOCINQ/OUTQ */ #include <linux/notifier.h> #include <linux/init.h> +#include <linux/compat.h> + #include <net/x25.h> +#include <net/compat.h> int sysctl_x25_restart_request_timeout = X25_DEFAULT_T20; int sysctl_x25_call_request_timeout = X25_DEFAULT_T21; @@ -69,6 +72,14 @@ static const struct proto_ops x25_proto_ops; static struct x25_address null_x25_address = {" "}; +#ifdef CONFIG_COMPAT +struct compat_x25_subscrip_struct { + char device[200-sizeof(compat_ulong_t)]; + compat_ulong_t global_facil_mask; + compat_uint_t extended; +}; +#endif + int x25_addr_ntoa(unsigned char *p, struct x25_address *called_addr, struct x25_address *calling_addr) { @@ -514,6 +525,13 @@ static int x25_create(struct socket *sock, int protocol) x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE; x25->facilities.throughput = X25_DEFAULT_THROUGHPUT; x25->facilities.reverse = X25_DEFAULT_REVERSE; + x25->dte_facilities.calling_len = 0; + x25->dte_facilities.called_len = 0; + memset(x25->dte_facilities.called_ae, '\0', + sizeof(x25->dte_facilities.called_ae)); + memset(x25->dte_facilities.calling_ae, '\0', + sizeof(x25->dte_facilities.calling_ae)); + rc = 0; out: return rc; @@ -550,6 +568,7 @@ static struct sock *x25_make_new(struct sock *osk) x25->t2 = ox25->t2; x25->facilities = ox25->facilities; x25->qbitincl = ox25->qbitincl; + x25->dte_facilities = ox25->dte_facilities; x25->cudmatchlength = ox25->cudmatchlength; x25->accptapprv = ox25->accptapprv; @@ -733,7 +752,7 @@ out: return rc; } -static int x25_wait_for_data(struct sock *sk, int timeout) +static int x25_wait_for_data(struct sock *sk, long timeout) { DECLARE_WAITQUEUE(wait, current); int rc = 0; @@ -829,6 +848,7 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, struct x25_sock *makex25; struct x25_address source_addr, dest_addr; struct x25_facilities facilities; + struct x25_dte_facilities dte_facilities; int len, rc; /* @@ -865,7 +885,8 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, /* * Try to reach a compromise on the requested facilities. */ - if ((len = x25_negotiate_facilities(skb, sk, &facilities)) == -1) + len = x25_negotiate_facilities(skb, sk, &facilities, &dte_facilities); + if (len == -1) goto out_sock_put; /* @@ -896,9 +917,12 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, makex25->source_addr = source_addr; makex25->neighbour = nb; makex25->facilities = facilities; + makex25->dte_facilities= dte_facilities; makex25->vc_facil_mask = x25_sk(sk)->vc_facil_mask; /* ensure no reverse facil on accept */ makex25->vc_facil_mask &= ~X25_MASK_REVERSE; + /* ensure no calling address extension on accept */ + makex25->vc_facil_mask &= ~X25_MASK_CALLING_AE; makex25->cudmatchlength = x25_sk(sk)->cudmatchlength; /* Normally all calls are accepted immediatly */ @@ -1305,6 +1329,36 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) break; } + case SIOCX25GDTEFACILITIES: { + rc = copy_to_user(argp, &x25->dte_facilities, + sizeof(x25->dte_facilities)); + if (rc) + rc = -EFAULT; + break; + } + + case SIOCX25SDTEFACILITIES: { + struct x25_dte_facilities dtefacs; + rc = -EFAULT; + if (copy_from_user(&dtefacs, argp, sizeof(dtefacs))) + break; + rc = -EINVAL; + if (sk->sk_state != TCP_LISTEN && + sk->sk_state != TCP_CLOSE) + break; + if (dtefacs.calling_len > X25_MAX_AE_LEN) + break; + if (dtefacs.calling_ae == NULL) + break; + if (dtefacs.called_len > X25_MAX_AE_LEN) + break; + if (dtefacs.called_ae == NULL) + break; + x25->dte_facilities = dtefacs; + rc = 0; + break; + } + case SIOCX25GCALLUSERDATA: { struct x25_calluserdata cud = x25->calluserdata; rc = copy_to_user(argp, &cud, @@ -1387,6 +1441,118 @@ static struct net_proto_family x25_family_ops = { .owner = THIS_MODULE, }; +#ifdef CONFIG_COMPAT +static int compat_x25_subscr_ioctl(unsigned int cmd, + struct compat_x25_subscrip_struct __user *x25_subscr32) +{ + struct compat_x25_subscrip_struct x25_subscr; + struct x25_neigh *nb; + struct net_device *dev; + int rc = -EINVAL; + + rc = -EFAULT; + if (copy_from_user(&x25_subscr, x25_subscr32, sizeof(*x25_subscr32))) + goto out; + + rc = -EINVAL; + dev = x25_dev_get(x25_subscr.device); + if (dev == NULL) + goto out; + + nb = x25_get_neigh(dev); + if (nb == NULL) + goto out_dev_put; + + dev_put(dev); + + if (cmd == SIOCX25GSUBSCRIP) { + x25_subscr.extended = nb->extended; + x25_subscr.global_facil_mask = nb->global_facil_mask; + rc = copy_to_user(x25_subscr32, &x25_subscr, + sizeof(*x25_subscr32)) ? -EFAULT : 0; + } else { + rc = -EINVAL; + if (x25_subscr.extended == 0 || x25_subscr.extended == 1) { + rc = 0; + nb->extended = x25_subscr.extended; + nb->global_facil_mask = x25_subscr.global_facil_mask; + } + } + x25_neigh_put(nb); +out: + return rc; +out_dev_put: + dev_put(dev); + goto out; +} + +static int compat_x25_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = compat_ptr(arg); + struct sock *sk = sock->sk; + + int rc = -ENOIOCTLCMD; + + switch(cmd) { + case TIOCOUTQ: + case TIOCINQ: + rc = x25_ioctl(sock, cmd, (unsigned long)argp); + break; + case SIOCGSTAMP: + rc = -EINVAL; + if (sk) + rc = compat_sock_get_timestamp(sk, + (struct timeval __user*)argp); + break; + case SIOCGIFADDR: + case SIOCSIFADDR: + case SIOCGIFDSTADDR: + case SIOCSIFDSTADDR: + case SIOCGIFBRDADDR: + case SIOCSIFBRDADDR: + case SIOCGIFNETMASK: + case SIOCSIFNETMASK: + case SIOCGIFMETRIC: + case SIOCSIFMETRIC: + rc = -EINVAL; + break; + case SIOCADDRT: + case SIOCDELRT: + rc = -EPERM; + if (!capable(CAP_NET_ADMIN)) + break; + rc = x25_route_ioctl(cmd, argp); + break; + case SIOCX25GSUBSCRIP: + rc = compat_x25_subscr_ioctl(cmd, argp); + break; + case SIOCX25SSUBSCRIP: + rc = -EPERM; + if (!capable(CAP_NET_ADMIN)) + break; + rc = compat_x25_subscr_ioctl(cmd, argp); + break; + case SIOCX25GFACILITIES: + case SIOCX25SFACILITIES: + case SIOCX25GDTEFACILITIES: + case SIOCX25SDTEFACILITIES: + case SIOCX25GCALLUSERDATA: + case SIOCX25SCALLUSERDATA: + case SIOCX25GCAUSEDIAG: + case SIOCX25SCUDMATCHLEN: + case SIOCX25CALLACCPTAPPRV: + case SIOCX25SENDCALLACCPT: + rc = x25_ioctl(sock, cmd, (unsigned long)argp); + break; + default: + rc = -ENOIOCTLCMD; + break; + } + return rc; +} +#endif + static const struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = { .family = AF_X25, .owner = THIS_MODULE, @@ -1398,6 +1564,9 @@ static const struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = { .getname = x25_getname, .poll = datagram_poll, .ioctl = x25_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = compat_x25_ioctl, +#endif .listen = x25_listen, .shutdown = sock_no_shutdown, .setsockopt = x25_setsockopt, diff --git a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c index 54278b962f4..9f42b9c9de3 100644 --- a/net/x25/x25_facilities.c +++ b/net/x25/x25_facilities.c @@ -28,18 +28,28 @@ #include <net/x25.h> /* - * Parse a set of facilities into the facilities structure. Unrecognised + * Parse a set of facilities into the facilities structures. Unrecognised * facilities are written to the debug log file. */ -int x25_parse_facilities(struct sk_buff *skb, - struct x25_facilities *facilities, - unsigned long *vc_fac_mask) +int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, + struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask) { unsigned char *p = skb->data; unsigned int len = *p++; *vc_fac_mask = 0; + /* + * The kernel knows which facilities were set on an incoming call but + * currently this information is not available to userspace. Here we + * give userspace who read incoming call facilities 0 length to indicate + * it wasn't set. + */ + dte_facs->calling_len = 0; + dte_facs->called_len = 0; + memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae)); + memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae)); + while (len > 0) { switch (*p & X25_FAC_CLASS_MASK) { case X25_FAC_CLASS_A: @@ -74,6 +84,8 @@ int x25_parse_facilities(struct sk_buff *skb, facilities->throughput = p[1]; *vc_fac_mask |= X25_MASK_THROUGHPUT; break; + case X25_MARKER: + break; default: printk(KERN_DEBUG "X.25: unknown facility " "%02X, value %02X\n", @@ -112,11 +124,30 @@ int x25_parse_facilities(struct sk_buff *skb, len -= 4; break; case X25_FAC_CLASS_D: - printk(KERN_DEBUG "X.25: unknown facility %02X, " - "length %d, values %02X, %02X, %02X, %02X\n", - p[0], p[1], p[2], p[3], p[4], p[5]); + switch (*p) { + case X25_FAC_CALLING_AE: + if (p[1] > X25_MAX_DTE_FACIL_LEN) + break; + dte_facs->calling_len = p[2]; + memcpy(dte_facs->calling_ae, &p[3], p[1] - 1); + *vc_fac_mask |= X25_MASK_CALLING_AE; + break; + case X25_FAC_CALLED_AE: + if (p[1] > X25_MAX_DTE_FACIL_LEN) + break; + dte_facs->called_len = p[2]; + memcpy(dte_facs->called_ae, &p[3], p[1] - 1); + *vc_fac_mask |= X25_MASK_CALLED_AE; + break; + default: + printk(KERN_DEBUG "X.25: unknown facility %02X," + "length %d, values %02X, %02X, " + "%02X, %02X\n", + p[0], p[1], p[2], p[3], p[4], p[5]); + break; + } len -= p[1] + 2; - p += p[1] + 2; + p += p[1] + 2; break; } } @@ -128,8 +159,8 @@ int x25_parse_facilities(struct sk_buff *skb, * Create a set of facilities. */ int x25_create_facilities(unsigned char *buffer, - struct x25_facilities *facilities, - unsigned long facil_mask) + struct x25_facilities *facilities, + struct x25_dte_facilities *dte_facs, unsigned long facil_mask) { unsigned char *p = buffer + 1; int len; @@ -168,6 +199,33 @@ int x25_create_facilities(unsigned char *buffer, *p++ = facilities->winsize_out ? : facilities->winsize_in; } + if (facil_mask & (X25_MASK_CALLING_AE|X25_MASK_CALLED_AE)) { + *p++ = X25_MARKER; + *p++ = X25_DTE_SERVICES; + } + + if (dte_facs->calling_len && (facil_mask & X25_MASK_CALLING_AE)) { + unsigned bytecount = (dte_facs->calling_len % 2) ? + dte_facs->calling_len / 2 + 1 : + dte_facs->calling_len / 2; + *p++ = X25_FAC_CALLING_AE; + *p++ = 1 + bytecount; + *p++ = dte_facs->calling_len; + memcpy(p, dte_facs->calling_ae, bytecount); + p += bytecount; + } + + if (dte_facs->called_len && (facil_mask & X25_MASK_CALLED_AE)) { + unsigned bytecount = (dte_facs->called_len % 2) ? + dte_facs->called_len / 2 + 1 : + dte_facs->called_len / 2; + *p++ = X25_FAC_CALLED_AE; + *p++ = 1 + bytecount; + *p++ = dte_facs->called_len; + memcpy(p, dte_facs->called_ae, bytecount); + p+=bytecount; + } + len = p - buffer; buffer[0] = len - 1; @@ -180,7 +238,7 @@ int x25_create_facilities(unsigned char *buffer, * The only real problem is with reverse charging. */ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, - struct x25_facilities *new) + struct x25_facilities *new, struct x25_dte_facilities *dte) { struct x25_sock *x25 = x25_sk(sk); struct x25_facilities *ours = &x25->facilities; @@ -190,7 +248,7 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, memset(&theirs, 0, sizeof(theirs)); memcpy(new, ours, sizeof(*new)); - len = x25_parse_facilities(skb, &theirs, &x25->vc_facil_mask); + len = x25_parse_facilities(skb, &theirs, dte, &x25->vc_facil_mask); /* * They want reverse charging, we won't accept it. diff --git a/net/x25/x25_in.c b/net/x25/x25_in.c index 26146874b83..eed50e10f09 100644 --- a/net/x25/x25_in.c +++ b/net/x25/x25_in.c @@ -106,7 +106,8 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr)); skb_pull(skb, x25_parse_facilities(skb, &x25->facilities, - &x25->vc_facil_mask)); + &x25->dte_facilities, + &x25->vc_facil_mask)); /* * Copy any Call User Data. */ diff --git a/net/x25/x25_subr.c b/net/x25/x25_subr.c index 8be9b8fbc24..8d6220aa5d0 100644 --- a/net/x25/x25_subr.c +++ b/net/x25/x25_subr.c @@ -190,8 +190,9 @@ void x25_write_internal(struct sock *sk, int frametype) dptr = skb_put(skb, len); memcpy(dptr, addresses, len); len = x25_create_facilities(facilities, - &x25->facilities, - x25->neighbour->global_facil_mask); + &x25->facilities, + &x25->dte_facilities, + x25->neighbour->global_facil_mask); dptr = skb_put(skb, len); memcpy(dptr, facilities, len); dptr = skb_put(skb, x25->calluserdata.cudlength); @@ -206,6 +207,7 @@ void x25_write_internal(struct sock *sk, int frametype) *dptr++ = 0x00; /* Address lengths */ len = x25_create_facilities(facilities, &x25->facilities, + &x25->dte_facilities, x25->vc_facil_mask); dptr = skb_put(skb, len); memcpy(dptr, facilities, len); |