static void timod_ok(int fd, int prim) { struct file *fp; struct T_primsg *it; struct T_ok_ack *ok; #if defined(CONFIG_ABI_TRACE) abi_trace(ABI_TRACE_STREAMS, "TI: %u ok ack prim=%d\n", fd, prim); #endif fp = fcheck(fd); it = timod_mkctl(sizeof(struct T_ok_ack)); if (!it) return; ok = (struct T_ok_ack *)&it->type; ok->PRIM_type = T_OK_ACK; ok->CORRECT_prim = prim; it->pri = MSG_HIPRI; it->length = sizeof(struct T_ok_ack); it->next = Priv(fp)->pfirst; Priv(fp)->pfirst = it; if (!Priv(fp)->plast) Priv(fp)->plast = it; timod_socket_wakeup(fp); }
static void timod_error(int fd, int prim, int terr, int uerr) { struct file *fp; struct T_primsg *it; struct T_error_ack *err; #if defined(CONFIG_ABI_TRACE) abi_trace(ABI_TRACE_STREAMS, "TI: %u error prim=%d, TLI=%d, UNIX=%d\n", fd, prim, terr, uerr); #endif fp = fcheck(fd); it = timod_mkctl(sizeof(struct T_error_ack)); if (!it) return; err = (struct T_error_ack *)&it->type; err->PRIM_type = T_ERROR_ACK; err->ERROR_prim = prim; err->TLI_error = terr; err->UNIX_error = iABI_errors(uerr); it->pri = MSG_HIPRI; it->length = sizeof(struct T_error_ack); it->next = Priv(fp)->pfirst; Priv(fp)->pfirst = it; if (!Priv(fp)->plast) Priv(fp)->plast = it; timod_socket_wakeup(fp); }
static void timod_ok(unsigned int fd, int prim) { struct T_primsg *it; struct T_ok_ack *ok; SOLD("creating ok ack"); it = timod_mkctl(sizeof(*ok)); if (it) { SOLD("got it"); ok = (struct T_ok_ack *)&it->type; ok->PRIM_type = T_OK_ACK; ok->CORRECT_prim = prim; timod_queue(fd, it); } SOLD("done"); }
static void timod_error(unsigned int fd, int prim, int terr, int uerr) { struct T_primsg *it; SOLD("making error"); it = timod_mkctl(sizeof(struct T_error_ack)); if (it) { struct T_error_ack *err = (struct T_error_ack *)&it->type; SOLD("got it"); err->PRIM_type = T_ERROR_ACK; err->ERROR_prim = prim; err->TLI_error = terr; err->UNIX_error = uerr; /* FIXME: convert this */ timod_queue(fd, it); } SOLD("done"); }
int timod_putmsg(unsigned int fd, char *ctl_buf, int ctl_len, char *data_buf, int data_len, int flags) { int ret, error, terror; char *buf; struct file *filp; struct inode *ino; struct sol_socket_struct *sock; mm_segment_t old_fs = get_fs(); long args[6]; int (*sys_socketcall)(int, unsigned long *) = (int (*)(int, unsigned long *))SYS(socketcall); int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int) = (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int))SYS(sendto); filp = current->files->fd[fd]; ino = filp->f_dentry->d_inode; sock = (struct sol_socket_struct *)filp->private_data; SOLD("entry"); if (get_user(ret, (int *)A(ctl_buf))) return -EFAULT; switch (ret) { case T_BIND_REQ: { struct T_bind_req req; SOLDD(("bind %016lx(%016lx)\n", sock, filp)); SOLD("T_BIND_REQ"); if (sock->state != TS_UNBND) { timod_error(fd, T_BIND_REQ, TOUTSTATE, 0); return 0; } SOLD("state ok"); if (copy_from_user(&req, ctl_buf, sizeof(req))) { timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT); return 0; } SOLD("got ctl req"); if (req.ADDR_offset && req.ADDR_length) { if (req.ADDR_length > BUF_SIZE) { timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT); return 0; } SOLD("req size ok"); buf = getpage(); if (copy_from_user(buf, ctl_buf + req.ADDR_offset, req.ADDR_length)) { timod_error(fd, T_BIND_REQ, TSYSERR, EFAULT); putpage(buf); return 0; } SOLD("got ctl data"); args[0] = fd; args[1] = (long)buf; args[2] = req.ADDR_length; SOLD("calling BIND"); set_fs(KERNEL_DS); error = sys_socketcall(SYS_BIND, args); set_fs(old_fs); putpage(buf); SOLD("BIND returned"); } else error = 0; if (!error) { struct T_primsg *it; if (req.CONIND_number) { args[0] = fd; args[1] = req.CONIND_number; SOLD("calling LISTEN"); set_fs(KERNEL_DS); error = sys_socketcall(SYS_LISTEN, args); set_fs(old_fs); SOLD("LISTEN done"); } it = timod_mkctl(sizeof(struct T_bind_ack)+sizeof(struct sockaddr)); if (it) { struct T_bind_ack *ack; ack = (struct T_bind_ack *)&it->type; ack->PRIM_type = T_BIND_ACK; ack->ADDR_offset = sizeof(*ack); ack->ADDR_length = sizeof(struct sockaddr); ack->CONIND_number = req.CONIND_number; args[0] = fd; args[1] = (long)(ack+sizeof(*ack)); args[2] = (long)&ack->ADDR_length; set_fs(KERNEL_DS); sys_socketcall(SYS_GETSOCKNAME,args); set_fs(old_fs); sock->state = TS_IDLE; timod_ok(fd, T_BIND_REQ); timod_queue_end(fd, it); SOLD("BIND done"); return 0; } } SOLD("some error"); switch (error) { case -EINVAL: terror = TOUTSTATE; error = 0; break; case -EACCES: terror = TACCES; error = 0; break; case -EADDRNOTAVAIL: case -EADDRINUSE: terror = TNOADDR; error = 0; break; default: terror = TSYSERR; break; } timod_error(fd, T_BIND_REQ, terror, -error); SOLD("BIND done"); return 0; } case T_CONN_REQ: { struct T_conn_req req; unsigned short oldflags; struct T_primsg *it; SOLD("T_CONN_REQ"); if (sock->state != TS_UNBND && sock->state != TS_IDLE) { timod_error(fd, T_CONN_REQ, TOUTSTATE, 0); return 0; } SOLD("state ok"); if (copy_from_user(&req, ctl_buf, sizeof(req))) { timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT); return 0; } SOLD("got ctl req"); if (ctl_len > BUF_SIZE) { timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT); return 0; } SOLD("req size ok"); buf = getpage(); if (copy_from_user(buf, ctl_buf, ctl_len)) { timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT); putpage(buf); return 0; } #ifdef DEBUG_SOLARIS { char * ptr = buf; int len = ctl_len; printk("returned data (%d bytes): ",len); while( len-- ) { if (!(len & 7)) printk(" "); printk("%02x",(unsigned char)*ptr++); } printk("\n"); } #endif SOLD("got ctl data"); args[0] = fd; args[1] = (long)buf+req.DEST_offset; args[2] = req.DEST_length; oldflags = filp->f_flags; filp->f_flags &= ~O_NONBLOCK; SOLD("calling CONNECT"); set_fs(KERNEL_DS); error = sys_socketcall(SYS_CONNECT, args); set_fs(old_fs); filp->f_flags = oldflags; SOLD("CONNECT done"); if (!error) { struct T_conn_con *con; SOLD("no error"); it = timod_mkctl(ctl_len); if (!it) { putpage(buf); return -ENOMEM; } con = (struct T_conn_con *)&it->type; #ifdef DEBUG_SOLARIS { char * ptr = buf; int len = ctl_len; printk("returned data (%d bytes): ",len); while( len-- ) { if (!(len & 7)) printk(" "); printk("%02x",(unsigned char)*ptr++); } printk("\n"); } #endif memcpy(con, buf, ctl_len); SOLD("copied ctl_buf"); con->PRIM_type = T_CONN_CON; sock->state = TS_DATA_XFER; } else { struct T_discon_ind *dis; SOLD("some error"); it = timod_mkctl(sizeof(*dis)); if (!it) { putpage(buf); return -ENOMEM; } SOLD("got primsg"); dis = (struct T_discon_ind *)&it->type; dis->PRIM_type = T_DISCON_IND; dis->DISCON_reason = -error; /* FIXME: convert this as in iABI_errors() */ dis->SEQ_number = 0; } putpage(buf); timod_ok(fd, T_CONN_REQ); it->pri = 0; timod_queue_end(fd, it); SOLD("CONNECT done"); return 0; } case T_OPTMGMT_REQ: { struct T_optmgmt_req req; SOLD("OPTMGMT_REQ"); if (copy_from_user(&req, ctl_buf, sizeof(req))) return -EFAULT; SOLD("got req"); return timod_optmgmt(fd, req.MGMT_flags, req.OPT_offset > 0 ? ctl_buf + req.OPT_offset : NULL, req.OPT_length, 1); } case T_UNITDATA_REQ: { struct T_unitdata_req req; int err; SOLD("T_UNITDATA_REQ"); if (sock->state != TS_IDLE && sock->state != TS_DATA_XFER) { timod_error(fd, T_CONN_REQ, TOUTSTATE, 0); return 0; } SOLD("state ok"); if (copy_from_user(&req, ctl_buf, sizeof(req))) { timod_error(fd, T_CONN_REQ, TSYSERR, EFAULT); return 0; } SOLD("got ctl req"); #ifdef DEBUG_SOLARIS { char * ptr = ctl_buf+req.DEST_offset; int len = req.DEST_length; printk("socket address (%d bytes): ",len); while( len-- ) { char c; if (get_user(c,ptr)) printk("??"); else printk("%02x",(unsigned char)c); ptr++; } printk("\n"); } #endif err = sys_sendto(fd, data_buf, data_len, 0, req.DEST_length > 0 ? (struct sockaddr*)(ctl_buf+req.DEST_offset) : NULL, req.DEST_length); if (err == data_len) return 0; if(err >= 0) { printk("timod: sendto failed to send all the data\n"); return 0; } timod_error(fd, T_CONN_REQ, TSYSERR, -err); return 0; } default: printk(KERN_INFO "timod_putmsg: unsupported command %u.\n", ret); break; } return -EINVAL; }
static int timod_optmgmt(unsigned int fd, int flag, char *opt_buf, int opt_len, int do_ret) { int error, failed; int ret_space, ret_len; long args[5]; char *ret_pos,*ret_buf; int (*sys_socketcall)(int, unsigned long *) = (int (*)(int, unsigned long *))SYS(socketcall); mm_segment_t old_fs = get_fs(); SOLD("entry"); SOLDD(("fd %u flg %u buf %p len %u doret %u",fd,flag,opt_buf,opt_len,do_ret)); if (!do_ret && (!opt_buf || opt_len <= 0)) return 0; SOLD("getting page"); ret_pos = ret_buf = getpage(); ret_space = BUF_SIZE; ret_len = 0; error = failed = 0; SOLD("looping"); while(opt_len >= sizeof(struct opthdr)) { struct opthdr *opt; int orig_opt_len; SOLD("loop start"); opt = (struct opthdr *)ret_pos; if (ret_space < sizeof(struct opthdr)) { failed = TSYSERR; break; } SOLD("getting opthdr"); if (copy_from_user(opt, opt_buf, sizeof(struct opthdr)) || opt->len > opt_len) { failed = TBADOPT; break; } SOLD("got opthdr"); if (flag == T_NEGOTIATE) { char *buf; SOLD("handling T_NEGOTIATE"); buf = ret_pos + sizeof(struct opthdr); if (ret_space < opt->len + sizeof(struct opthdr) || copy_from_user(buf, opt_buf+sizeof(struct opthdr), opt->len)) { failed = TSYSERR; break; } SOLD("got optdata"); args[0] = fd; args[1] = opt->level; args[2] = opt->name; args[3] = (long)buf; args[4] = opt->len; SOLD("calling SETSOCKOPT"); set_fs(KERNEL_DS); error = sys_socketcall(SYS_SETSOCKOPT, args); set_fs(old_fs); if (error) { failed = TBADOPT; break; } SOLD("SETSOCKOPT ok"); } orig_opt_len = opt->len; opt->len = ret_space - sizeof(struct opthdr); if (opt->len < 0) { failed = TSYSERR; break; } args[0] = fd; args[1] = opt->level; args[2] = opt->name; args[3] = (long)(ret_pos+sizeof(struct opthdr)); args[4] = (long)&opt->len; SOLD("calling GETSOCKOPT"); set_fs(KERNEL_DS); error = sys_socketcall(SYS_GETSOCKOPT, args); set_fs(old_fs);; if (error) { failed = TBADOPT; break; } SOLD("GETSOCKOPT ok"); ret_space -= sizeof(struct opthdr) + opt->len; ret_len += sizeof(struct opthdr) + opt->len; ret_pos += sizeof(struct opthdr) + opt->len; opt_len -= sizeof(struct opthdr) + orig_opt_len; opt_buf += sizeof(struct opthdr) + orig_opt_len; SOLD("loop end"); } SOLD("loop done"); if (do_ret) { SOLD("generating ret msg"); if (failed) timod_error(fd, T_OPTMGMT_REQ, failed, -error); else { struct T_primsg *it; it = timod_mkctl(sizeof(struct T_optmgmt_ack) + ret_len); if (it) { struct T_optmgmt_ack *ack = (struct T_optmgmt_ack *)&it->type; SOLD("got primsg"); ack->PRIM_type = T_OPTMGMT_ACK; ack->OPT_length = ret_len; ack->OPT_offset = sizeof(struct T_optmgmt_ack); ack->MGMT_flags = (failed ? T_FAILURE : flag); memcpy(((char*)ack)+sizeof(struct T_optmgmt_ack), ret_buf, ret_len); timod_queue(fd, it); } } } SOLDD(("put_page %p\n", ret_buf)); putpage(ret_buf); SOLD("done"); return 0; }