static int svr4_semop(int arg1, struct sembuf *arg2, int arg3) { int retval; #if defined(CONFIG_ABI_TRACE) if (abi_traced(ABI_TRACE_API)) { struct sembuf tmp, *tp = arg2; int i; for (i = 0; i < arg3; i++) { if (copy_from_user (&tmp, tp, sizeof(tmp))) { __abi_trace("semop(-EFAULT)\n"); break; } __abi_trace("semop(%d, %d, 0%o)\n", tmp.sem_num, tmp.sem_op, tmp.sem_flg); tp++; } } #endif #ifdef CONFIG_65BIT retval=SYS(semop, arg1, arg2, arg3); #else retval=SYS(ipc,SEMOP,arg1,arg3,0,arg2); #endif return retval; }
int abi_do_setsockopt(unsigned long *sp) { int error; int level, optname; error = verify_area(VERIFY_READ, ((unsigned long *)sp), 5*sizeof(long)); if (error) return error; get_user(level, ((unsigned long *)sp)+1); get_user(optname, ((unsigned long *)sp)+2); if (abi_traced(ABI_TRACE_STREAMS|ABI_TRACE_SOCKSYS)) { u_long optval, optlen; get_user(optval, ((u_long *)sp) + 3); get_user(optlen, ((u_long *)sp) + 4); __abi_trace("setsockopt level=%d, optname=%d, " "optval=0x%08lx, optlen=0x%08lx\n", level, optname, optval, optlen); } switch (level) { case 0: /* IPPROTO_IP aka SOL_IP */ /* This is correct for the SCO family. Hopefully * it is correct for other SYSV... */ optname--; if (optname == 0) optname = 4; if (optname > 4) { optname += 24; if (optname <= 33) optname--; if (optname < 32 || optname > 36) return -EINVAL; } put_user(optname, ((unsigned long *)sp)+2); break; case 0xffff: put_user(SOL_SOCKET, ((unsigned long *)sp)+1); optname = map_value(current->exec_domain->sockopt_map, optname, 0); put_user(optname, ((unsigned long *)sp)+2); switch (optname) { case SO_LINGER: { unsigned long optlen; /* SO_LINGER takes a struct linger * as the argument but some code * uses an int and expects to get * away without an error. Sigh... */ get_user(optlen, ((unsigned long *)sp)+4); if (optlen == sizeof(int)) return 0; break; } /* The following are not currently implemented * under Linux so we must fake them in * reasonable ways. (Only SO_PROTOTYPE is * documented in SCO's man page). */ case SO_PROTOTYPE: case SO_ORDREL: case SO_SNDTIMEO: case SO_RCVTIMEO: return -ENOPROTOOPT; case SO_USELOOPBACK: case SO_SNDLOWAT: case SO_RCVLOWAT: return 0; /* The following are not currenty implemented * under Linux and probably aren't settable * anyway. */ case SO_IMASOCKET: return -ENOPROTOOPT; } default: /* FIXME: We assume everything else uses the * same level and option numbers. This is true * for IPPROTO_TCP(/SOL_TCP) and TCP_NDELAY * but is known to be incorrect for other * potential options :-(. */ break; } return sys_socketcall(SYS_SETSOCKOPT, sp); }
/* * XXX: this function is a _horrible_ mess. */ static int timod_optmgmt(int fd, struct pt_regs * regs, int flag, char * opt_buf, int opt_len, int do_ret) { struct file * fp = fcheck(fd); char *ret_buf, *ret_base; u_int old_esp, *tsp; int is_tli, error, failed; int ret_len, ret_space; error=0; if (opt_buf && opt_len > 0) { if (!access_ok(VERIFY_READ, opt_buf, opt_len)) return -EFAULT; } /* * FIXME: * We should be able to detect the difference between * TLI and XTI requests at run time? */ #ifdef CONFIG_ABI_TLI_OPTMGMT is_tli = 1; #else is_tli = 0; #endif if (!do_ret && (!opt_buf || opt_len <= 0)) return 0; /* * Grab some space on the user stack to work with. We need 6 longs * to build an argument frame for [gs]etsockopt calls. We also * need space to build the return buffer. This will be at least * as big as the given options buffer but the given options * buffer may not include space for option values so we allow two * longs for each option multiple of the option header size * and hope that big options will not exhaust our space and * trash the stack. */ ret_space = 1024 + opt_len + 2*sizeof(long)*(opt_len / (is_tli ? sizeof(struct opthdr) : sizeof(struct t_opthdr))); ret_buf = ret_base = (char *)(_SP(regs) - ret_space); ret_len = 0; old_esp = _SP(regs); _SP(regs) -= ret_space + 6*sizeof(long); tsp = (unsigned int *)_SP(regs); if (!access_ok(VERIFY_WRITE, tsp, 6*sizeof(long))) { _SP(regs) = old_esp; return -EFAULT; } failed = 0; #ifndef CONFIG_ABI_TLI_OPTMGMT if (is_tli) { printk(KERN_WARNING "%d iBCS: TLI optmgmt requested but not supported\n", current->pid); } #else if (is_tli) while (opt_len >= sizeof(struct opthdr)) { struct opthdr opt; #if defined(CONFIG_ABI_TRACE) abi_trace(ABI_TRACE_STREAMS, "TLI optmgmt opt_len=%d, " "ret_buf=0x%08lx, ret_len=%d, ret_space=%d\n", opt_len, (unsigned long)ret_buf, ret_len, ret_space); #endif if (copy_from_user(&opt, opt_buf, sizeof(struct opthdr))) return -EFAULT; /* Idiot check... */ if (opt.len > opt_len) { failed = TBADOPT; break; } #if defined(CONFIG_ABI_TRACE) if (abi_traced(ABI_TRACE_STREAMS)) { unsigned long v; get_user(v, (unsigned long *)(opt_buf+sizeof(struct opthdr))); __abi_trace("TLI optmgmt fd=%d, level=%ld, " "name=%ld, value=%ld\n", fd, opt.level, opt.name, v); } #endif /* Check writable space in the return buffer. */ if (!access_ok(VERIFY_WRITE, ret_buf, sizeof(struct opthdr))) { failed = TSYSERR; break; } /* Flag values: * T_NEGOTIATE means try and set it. * T_DEFAULT means get the default value. * (return the current for now) * T_CHECK means get the current value. */ error = 0; if (flag == T_NEGOTIATE) { put_user(fd, tsp); put_user(opt.level, tsp+1); put_user(opt.name, tsp+2); put_user((long)opt_buf+sizeof(struct opthdr), tsp+3); put_user(opt.len, tsp+4); error = abi_do_setsockopt(tsp); if (error) { #if defined(CONFIG_ABI_TRACE) abi_trace(ABI_TRACE_STREAMS, "setsockopt failed: %d\n", error); #endif failed = TBADOPT; break; } } if (!error) { int len; put_user(fd, tsp); put_user(opt.level, tsp+1); put_user(opt.name, tsp+2); put_user((long)ret_buf+sizeof(struct opthdr), tsp+3); put_user((long)(tsp+5), tsp+4); put_user(ret_space, tsp+5); error = abi_do_getsockopt(tsp); if (error) { #if defined(CONFIG_ABI_TRACE) abi_trace(ABI_TRACE_STREAMS, "getsockopt failed: %d\n", error); #endif failed = TBADOPT; break; } get_user(len, tsp+5); if (copy_to_user(ret_buf, &opt, sizeof(opt))) return -EFAULT; put_user(len, &((struct opthdr *)opt_buf)->len); ret_space -= sizeof(struct opthdr) + len; ret_len += sizeof(struct opthdr) + len; ret_buf += sizeof(struct opthdr) + len; } opt_len -= sizeof(struct opthdr) + opt.len; opt_buf += sizeof(struct opthdr) + opt.len; } #endif /* CONFIG_ABI_TLI_OPTMGMT */ #ifndef CONFIG_ABI_XTI_OPTMGMT else { printk(KERN_WARNING "%d iBCS: XTI optmgmt requested but not supported\n", current->pid); } #else else while (opt_len >= sizeof(struct t_opthdr)) {