/****************************************************************************** * sysctl.c * * System management operations. For use by node control stack. * * Copyright (c) 2002-2006, K Fraser */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern int do_get_pm_info(struct xen_sysctl_get_pmstat *op); extern int do_pm_op(struct xen_sysctl_pm_op *op); extern long arch_do_sysctl( struct xen_sysctl *op, XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl); long do_sysctl(XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl) { long ret = 0; struct xen_sysctl curop, *op = &curop; static DEFINE_SPINLOCK(sysctl_lock); if ( !IS_PRIV(current->domain) ) return -EPERM; if ( copy_from_guest(op, u_sysctl, 1) ) return -EFAULT; if ( op->interface_version != XEN_SYSCTL_INTERFACE_VERSION ) return -EACCES; spin_lock(&sysctl_lock); switch ( op->cmd ) { case XEN_SYSCTL_readconsole: { ret = xsm_readconsole(op->u.readconsole.clear); if ( ret ) break; ret = read_console_ring(&op->u.readconsole); if ( copy_to_guest(u_sysctl, op, 1) ) ret = -EFAULT; } break; case XEN_SYSCTL_tbuf_op: { ret = xsm_tbufcontrol(); if ( ret ) break; ret = tb_control(&op->u.tbuf_op); if ( copy_to_guest(u_sysctl, op, 1) ) ret = -EFAULT; } break; case XEN_SYSCTL_sched_id: { ret = xsm_sched_id(); if ( ret ) break; op->u.sched_id.sched_id = sched_id(); if ( copy_to_guest(u_sysctl, op, 1) ) ret = -EFAULT; else ret = 0; } break; case XEN_SYSCTL_getdomaininfolist: { struct domain *d; struct xen_domctl_getdomaininfo info; u32 num_domains = 0; rcu_read_lock(&domlist_read_lock); for_each_domain ( d ) { if ( d->domain_id < op->u.getdomaininfolist.first_domain ) continue; if ( num_domains == op->u.getdomaininfolist.max_domains ) break; ret = xsm_getdomaininfo(d); if ( ret ) continue; getdomaininfo(d, &info); if ( copy_to_guest_offset(op->u.getdomaininfolist.buffer, num_domains, &info, 1) ) { ret = -EFAULT; break; } num_domains++; } rcu_read_unlock(&domlist_read_lock); if ( ret != 0 ) break; op->u.getdomaininfolist.num_domains = num_domains; if ( copy_to_guest(u_sysctl, op, 1) ) ret = -EFAULT; } break; #ifdef PERF_COUNTERS case XEN_SYSCTL_perfc_op: { ret = xsm_perfcontrol(); if ( ret ) break; ret = perfc_control(&op->u.perfc_op); if ( copy_to_guest(u_sysctl, op, 1) ) ret = -EFAULT; } break; #endif case XEN_SYSCTL_debug_keys: { char c; uint32_t i; ret = xsm_debug_keys(); if ( ret ) break; for ( i = 0; i < op->u.debug_keys.nr_keys; i++ ) { if ( copy_from_guest_offset(&c, op->u.debug_keys.keys, i, 1) ) return -EFAULT; handle_keypress(c, guest_cpu_user_regs()); } } break; case XEN_SYSCTL_getcpuinfo: { uint32_t i, nr_cpus; struct xen_sysctl_cpuinfo cpuinfo; nr_cpus = min_t(uint32_t, op->u.getcpuinfo.max_cpus, NR_CPUS); ret = xsm_getcpuinfo(); if ( ret ) break; for ( i = 0; i < nr_cpus; i++ ) { cpuinfo.idletime = get_cpu_idle_time(i); ret = -EFAULT; if ( copy_to_guest_offset(op->u.getcpuinfo.info, i, &cpuinfo, 1) ) goto out; } op->u.getcpuinfo.nr_cpus = i; ret = copy_to_guest(u_sysctl, op, 1) ? -EFAULT : 0; } break; case XEN_SYSCTL_availheap: { ret = xsm_availheap(); if ( ret ) break; op->u.availheap.avail_bytes = avail_domheap_pages_region( op->u.availheap.node, op->u.availheap.min_bitwidth, op->u.availheap.max_bitwidth); op->u.availheap.avail_bytes <<= PAGE_SHIFT; ret = copy_to_guest(u_sysctl, op, 1) ? -EFAULT : 0; } break; case XEN_SYSCTL_get_pmstat: { ret = xsm_get_pmstat(); if ( ret ) break; ret = do_get_pm_info(&op->u.get_pmstat); if ( ret ) break; if ( copy_to_guest(u_sysctl, op, 1) ) { ret = -EFAULT; break; } } break; case XEN_SYSCTL_pm_op: { ret = xsm_pm_op(); if ( ret ) break; ret = do_pm_op(&op->u.pm_op); if ( ret && (ret != -EAGAIN) ) break; if ( copy_to_guest(u_sysctl, op, 1) ) { ret = -EFAULT; break; } } break; case XEN_SYSCTL_page_offline_op: { uint32_t *status, *ptr; unsigned long pfn; ptr = status = xmalloc_bytes( sizeof(uint32_t) * (op->u.page_offline.end - op->u.page_offline.start + 1)); if ( !status ) { dprintk(XENLOG_WARNING, "Out of memory for page offline op\n"); ret = -ENOMEM; break; } memset(status, PG_OFFLINE_INVALID, sizeof(uint32_t) * (op->u.page_offline.end - op->u.page_offline.start + 1)); for ( pfn = op->u.page_offline.start; pfn <= op->u.page_offline.end; pfn ++ )
#ifndef __LINUX_IF_ADDR_H
#define __LINUX_IF_ADDR_H

#include <linux/netlink.h>

struct ifaddrmsg
{
	__u8		ifa_family;
	__u8		ifa_prefixlen;	/* The prefix length		*/
	__u8		ifa_flags;	/* Flags			*/
	__u8		ifa_scope;	/* Address scope		*/
	__u32		ifa_index;	/* Link index			*/
};

/*
 * Important comment:
 * IFA_ADDRESS is prefix address, rather than local interface address.
 * It makes no difference for normally configured broadcast interfaces,
 * but for point-to-point IFA_ADDRESS is DESTINATION address,
 * local address is supplied in IFA_LOCAL attribute.
 */
enum
{
	IFA_UNSPEC,
	IFA_ADDRESS,
	IFA_LOCAL,
	IFA_LABEL,
	IFA_BROADCAST,
	IFA_ANYCAST,
	IFA_CACHEINFO,
	IFA_MULTICAST,
	__IFA_MAX,
};

#define IFA_MAX (__IFA_MAX - 1)

/* ifa_flags */
#define IFA_F_SECONDARY		0x01
#define IFA_F_TEMPORARY		IFA_F_SECONDARY

#define	IFA_F_NODAD		0x02
#define IFA_F_OPTIMISTIC	0x04
#define	IFA_F_HOMEADDRESS	0x10
#define IFA_F_DEPRECATED	0x20
#define IFA_F_TENTATIVE		0x40
#define IFA_F_PERMANENT		0x80

struct ifa_cacheinfo
{
	__u32	ifa_prefered;
	__u32	ifa_valid;
	__u32	cstamp; /* created timestamp, hundredths of seconds */
	__u32	tstamp; /* updated timestamp, hundredths of seconds */
};

/* backwards compatibility for userspace */
#ifndef __KERNEL__
#define IFA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
#endif

#endif