📄 sock.c
字号:
break;
case SO_LINGER:
err=verify_area(VERIFY_WRITE,optval,sizeof(ling));
if(err)
return err;
err=verify_area(VERIFY_WRITE,optlen,sizeof(int));
if(err)
return err;
put_fs_long(sizeof(ling),(unsigned long *)optlen);
ling.l_onoff=sk->linger;
ling.l_linger=sk->lingertime;
memcpy_tofs(optval,&ling,sizeof(ling));
return 0;
case SO_SNDBUF:
val=sk->sndbuf;
break;
case SO_RCVBUF:
val =sk->rcvbuf;
break;
case SO_REUSEADDR:
val = sk->reuse;
break;
case SO_KEEPALIVE:
val = sk->keepopen;
break;
case SO_TYPE:
if (sk->prot == &tcp_prot)
val = SOCK_STREAM;
else
val = SOCK_DGRAM;
break;
case SO_ERROR:
val = sk->err;
sk->err = 0;
break;
case SO_OOBINLINE:
val = sk->urginline;
break;
case SO_NO_CHECK:
val = sk->no_check;
break;
case SO_PRIORITY:
val = sk->priority;
break;
default:
return(-ENOPROTOOPT);
}
err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
if(err)
return err;
put_fs_long(sizeof(int),(unsigned long *) optlen);
err=verify_area(VERIFY_WRITE, optval, sizeof(int));
if(err)
return err;
put_fs_long(val,(unsigned long *)optval);
return(0);
}
static int
inet_listen(struct socket *sock, int backlog)
{
struct sock *sk;
sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
}
/* We may need to bind the socket. */
if (sk->num == 0) {
sk->num = get_new_socknum(sk->prot, 0);
if (sk->num == 0) return(-EAGAIN);
put_sock(sk->num, sk);
sk->dummy_th.source = ntohs(sk->num);
}
/* We might as well re use these. */
sk->max_ack_backlog = backlog;
if (sk->state != TCP_LISTEN) {
sk->ack_backlog = 0;
sk->state = TCP_LISTEN;
}
return(0);
}
/*
* Default callbacks for user INET sockets. These just wake up
* the user owning the socket.
*/
static void def_callback1(struct sock *sk)
{
if(!sk->dead)
wake_up_interruptible(sk->sleep);
}
static void def_callback2(struct sock *sk,int len)
{
if(!sk->dead)
wake_up_interruptible(sk->sleep);
}
static int
inet_create(struct socket *sock, int protocol)
{
struct sock *sk;
struct proto *prot;
int err;
sk = (struct sock *) kmalloc(sizeof(*sk), GFP_KERNEL);
if (sk == NULL)
return(-ENOMEM);
sk->num = 0;
sk->reuse = 0;
switch(sock->type) {
case SOCK_STREAM:
case SOCK_SEQPACKET:
if (protocol && protocol != IPPROTO_TCP) {
kfree_s((void *)sk, sizeof(*sk));
return(-EPROTONOSUPPORT);
}
protocol = IPPROTO_TCP;
sk->no_check = TCP_NO_CHECK;
prot = &tcp_prot;
break;
case SOCK_DGRAM:
if (protocol && protocol != IPPROTO_UDP) {
kfree_s((void *)sk, sizeof(*sk));
return(-EPROTONOSUPPORT);
}
protocol = IPPROTO_UDP;
sk->no_check = UDP_NO_CHECK;
prot=&udp_prot;
break;
case SOCK_RAW:
if (!suser()) {
kfree_s((void *)sk, sizeof(*sk));
return(-EPERM);
}
if (!protocol) {
kfree_s((void *)sk, sizeof(*sk));
return(-EPROTONOSUPPORT);
}
prot = &raw_prot;
sk->reuse = 1;
sk->no_check = 0; /*
* Doesn't matter no checksum is
* preformed anyway.
*/
sk->num = protocol;
break;
case SOCK_PACKET:
if (!suser()) {
kfree_s((void *)sk, sizeof(*sk));
return(-EPERM);
}
if (!protocol) {
kfree_s((void *)sk, sizeof(*sk));
return(-EPROTONOSUPPORT);
}
prot = &packet_prot;
sk->reuse = 1;
sk->no_check = 0; /* Doesn't matter no checksum is
* preformed anyway.
*/
sk->num = protocol;
break;
default:
kfree_s((void *)sk, sizeof(*sk));
return(-ESOCKTNOSUPPORT);
}
sk->socket = sock;
#ifdef CONFIG_TCP_NAGLE_OFF
sk->nonagle = 1;
#else
sk->nonagle = 0;
#endif
sk->type = sock->type;
sk->protocol = protocol;
sk->wmem_alloc = 0;
sk->rmem_alloc = 0;
sk->sndbuf = SK_WMEM_MAX;
sk->rcvbuf = SK_RMEM_MAX;
sk->pair = NULL;
sk->opt = NULL;
sk->write_seq = 0;
sk->acked_seq = 0;
sk->copied_seq = 0;
sk->fin_seq = 0;
sk->urg_seq = 0;
sk->urg_data = 0;
sk->proc = 0;
sk->rtt = TCP_WRITE_TIME << 3;
sk->rto = TCP_WRITE_TIME;
sk->mdev = 0;
sk->backoff = 0;
sk->packets_out = 0;
sk->cong_window = 1; /* start with only sending one packet at a time. */
sk->cong_count = 0;
sk->ssthresh = 0;
sk->max_window = 0;
sk->urginline = 0;
sk->intr = 0;
sk->linger = 0;
sk->destroy = 0;
sk->priority = 1;
sk->shutdown = 0;
sk->keepopen = 0;
sk->zapped = 0;
sk->done = 0;
sk->ack_backlog = 0;
sk->window = 0;
sk->bytes_rcv = 0;
sk->state = TCP_CLOSE;
sk->dead = 0;
sk->ack_timed = 0;
sk->partial = NULL;
sk->user_mss = 0;
sk->debug = 0;
/* this is how many unacked bytes we will accept for this socket. */
sk->max_unacked = 2048; /* needs to be at most 2 full packets. */
/* how many packets we should send before forcing an ack.
if this is set to zero it is the same as sk->delay_acks = 0 */
sk->max_ack_backlog = 0;
sk->inuse = 0;
sk->delay_acks = 0;
sk->wback = NULL;
sk->wfront = NULL;
sk->rqueue = NULL;
sk->mtu = 576;
sk->prot = prot;
sk->sleep = sock->wait;
sk->daddr = 0;
sk->saddr = my_addr();
sk->err = 0;
sk->next = NULL;
sk->pair = NULL;
sk->send_tail = NULL;
sk->send_head = NULL;
sk->timeout = 0;
sk->broadcast = 0;
sk->timer.data = (unsigned long)sk;
sk->timer.function = &net_timer;
sk->back_log = NULL;
sk->blog = 0;
sock->data =(void *) sk;
sk->dummy_th.doff = sizeof(sk->dummy_th)/4;
sk->dummy_th.res1=0;
sk->dummy_th.res2=0;
sk->dummy_th.urg_ptr = 0;
sk->dummy_th.fin = 0;
sk->dummy_th.syn = 0;
sk->dummy_th.rst = 0;
sk->dummy_th.psh = 0;
sk->dummy_th.ack = 0;
sk->dummy_th.urg = 0;
sk->dummy_th.dest = 0;
sk->ip_tos=0;
sk->ip_ttl=64;
sk->state_change = def_callback1;
sk->data_ready = def_callback2;
sk->write_space = def_callback1;
sk->error_report = def_callback1;
if (sk->num) {
/*
* It assumes that any protocol which allows
* the user to assign a number at socket
* creation time automatically
* shares.
*/
put_sock(sk->num, sk);
sk->dummy_th.source = ntohs(sk->num);
}
if (sk->prot->init) {
err = sk->prot->init(sk);
if (err != 0) {
destroy_sock(sk);
return(err);
}
}
return(0);
}
static int
inet_dup(struct socket *newsock, struct socket *oldsock)
{
return(inet_create(newsock,
((struct sock *)(oldsock->data))->protocol));
}
/* The peer socket should always be NULL. */
static int
inet_release(struct socket *sock, struct socket *peer)
{
struct sock *sk;
sk = (struct sock *) sock->data;
if (sk == NULL) return(0);
DPRINTF((DBG_INET, "inet_release(sock = %X, peer = %X)\n", sock, peer));
sk->state_change(sk);
/* Start closing the connection. This may take a while. */
/*
* If linger is set, we don't return until the close
* is complete. Other wise we return immediately. The
* actually closing is done the same either way.
*/
if (sk->linger == 0) {
sk->prot->close(sk,0);
sk->dead = 1;
} else {
DPRINTF((DBG_INET, "sk->linger set.\n"));
sk->prot->close(sk, 0);
cli();
if (sk->lingertime)
current->timeout = jiffies + HZ*sk->lingertime;
while(sk->state != TCP_CLOSE && current->timeout>0) {
interruptible_sleep_on(sk->sleep);
if (current->signal & ~current->blocked) {
break;
#if 0
/* not working now - closes can't be restarted */
sti();
current->timeout=0;
return(-ERESTARTSYS);
#endif
}
}
current->timeout=0;
sti();
sk->dead = 1;
}
sk->inuse = 1;
/* This will destroy it. */
release_sock(sk);
sock->data = NULL;
DPRINTF((DBG_INET, "inet_release returning\n"));
return(0);
}
/* this needs to be changed to dissallow
the rebinding of sockets. What error
should it return? */
static int
inet_bind(struct socket *sock, struct sockaddr *uaddr,
int addr_len)
{
struct sockaddr_in addr;
struct sock *sk, *sk2;
unsigned short snum;
int err;
sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
}
/* check this error. */
if (sk->state != TCP_CLOSE) return(-EIO);
if (sk->num != 0) return(-EINVAL);
err=verify_area(VERIFY_READ, uaddr, addr_len);
if(err)
return err;
memcpy_fromfs(&addr, uaddr, min(sizeof(addr), addr_len));
snum = ntohs(addr.sin_port);
DPRINTF((DBG_INET, "bind sk =%X to port = %d\n", sk, snum));
sk = (struct sock *) sock->data;
/*
* We can't just leave the socket bound wherever it is, it might
* be bound to a privileged port. However, since there seems to
* be a bug here, we will leave it if the port is not privileged.
*/
if (snum == 0) {
snum = get_new_socknum(sk->prot, 0);
}
if (snum < PROT_SOCK && !suser()) return(-EACCES);
if (addr.sin_addr.s_addr!=0 && chk_addr(addr.sin_addr.s_addr)!=IS_MYADDR)
return(-EADDRNOTAVAIL); /* Source address MUST be ours! */
if (chk_addr(addr.sin_addr.s_addr) || addr.sin_addr.s_addr == 0)
sk->saddr = addr.sin_addr.s_addr;
DPRINTF((DBG_INET, "sock_array[%d] = %X:\n", snum &(SOCK_ARRAY_SIZE -1),
sk->prot->sock_array[snum &(SOCK_ARRAY_SIZE -1)]));
/* Make sure we are allowed to bind here. */
cli();
outside_loop:
for(sk2 = sk->prot->sock_array[snum & (SOCK_ARRAY_SIZE -1)];
sk2 != NULL; sk2 = sk2->next) {
#if 1 /* should be below! */
if (sk2->num != snum) continue;
/* if (sk2->saddr != sk->saddr) continue; */
#endif
if (sk2->dead) {
destroy_sock(sk2);
goto outside_loop;
}
if (!sk->reuse) {
sti();
return(-EADDRINUSE);
}
if (sk2->num != snum) continue; /* more than one */
if (sk2->saddr != sk->saddr) continue; /* socket per slot ! -FB */
if (!sk2->reuse) {
sti();
return(-EADDRINUSE);
}
}
sti();
remove_sock(sk);
put_sock(snum, sk);
sk->dummy_th.source = ntohs(sk->num);
sk->daddr = 0;
sk->dummy_th.dest = 0;
return(0);
}
static int
inet_connect(struct socket *sock, struct sockaddr * uaddr,
int addr_len, int flags)
{
struct sock *sk;
int err;
sock->conn = NULL;
sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
}
if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED)
{
sock->state = SS_CONNECTED;
/* Connection completing after a connect/EINPROGRESS/select/connect */
return 0; /* Rock and roll */
}
if (sock->state == SS_CONNECTING && sk->protocol == IPPROTO_TCP &&
(flags & O_NONBLOCK))
return -EALREADY; /* Connecting is currently in progress */
if (sock->state != SS_CONNECTING) {
/* We may need to bind the socket. */
if (sk->num == 0) {
sk->num = get_new_socknum(sk->prot, 0);
if (sk->num == 0)
return(-EAGAIN);
put_sock(sk->num, sk);
sk->dummy_th.source = htons(sk->num);
}
if (sk->prot->connect == NULL)
return(-EOPNOTSUPP);
err = sk->prot->connect(sk, (struct sockaddr_in *)uaddr, addr_len);
if (err < 0) return(err);
sock->state = SS_CONNECTING;
}
if (sk->state != TCP_ESTABLISHED &&(flags & O_NONBLOCK))
return(-EINPROGRESS);
cli(); /* avoid the race condition */
while(sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV)
{
interruptible_sleep_on(sk->sleep);
if (current->signal & ~current->blocked) {
sti();
return(-ERESTARTSYS);
}
/* This fixes a nasty in the tcp/ip code. There is a hideous hassle with
icmp error packets wanting to close a tcp or udp socket. */
if(sk->err && sk->protocol == IPPROTO_TCP)
{
sti();
sock->state = SS_UNCONNECTED;
err = -sk->err;
sk->err=0;
return err; /* set by tcp_err() */
}
}
sti();
sock->state = SS_CONNECTED;
if (sk->state != TCP_ESTABLISHED && sk->err) {
sock->state = SS_UNCONNECTED;
err=sk->err;
sk->err=0;
return(-err);
}
return(0);
}
static int
inet_socketpair(struct socket *sock1, struct socket *sock2)
{
return(-EOPNOTSUPP);
}
static int
inet_accept(struct socket *sock, struct socket *newsock, int flags)
{
struct sock *sk1, *sk2;
int err;
sk1 = (struct sock *) sock->data;
if (sk1 == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
}
/*
* We've been passed an extra socket.
* We need to free it up because the tcp module creates
* it's own when it accepts one.
*/
if (newsock->data) kfree_s(newsock->data, sizeof(struct sock));
newsock->data = NULL;
if (sk1->prot->accept == NULL) return(-EOPNOTSUPP);
/* Restore the state if we have been interrupted, and then returned. */
if (sk1->pair != NULL ) {
sk2 = sk1->pair;
sk1->pair = NULL;
} else {
sk2 = sk1->prot->accept(sk1,flags);
if (sk2 == NULL) {
if (sk1->err <= 0)
printk("Warning sock.c:sk1->err <= 0. Returning non-error.\n");
err=sk1->err;
sk1->err=0;
return(-err);
}
}
newsock->data = (void *)sk2;
sk2->sleep = newsock->wait;
newsock->conn = NULL;
if (flags & O_NONBLOCK) return(0);
cli(); /* avoid the race. */
while(sk2->state == TCP_SYN_RECV) {
interruptible_sleep_on(sk2->sleep);
if (current->signal & ~current->blocked) {
sti();
sk1->pair = sk2;
sk2->sleep = NULL;
newsock->data = NULL;
return(-ERESTARTSYS);
}
}
sti();
if (sk2->state != TCP_ESTABLISHED && sk2->err > 0) {
err = -sk2->err;
sk2->err=0;
destroy_sock(sk2);
newsock->data = NULL;
return(err);
}
newsock->state = SS_CONNECTED;
return(0);
}
static int
inet_getname(struct socket *sock, struct sockaddr *uaddr,
int *uaddr_len, int peer)
{
struct sockaddr_in sin;
struct sock *sk;
int len;
int err;
err = verify_area(VERIFY_WRITE,uaddr_len,sizeof(long));
if(err)
return err;
len=get_fs_long(uaddr_len);
err = verify_area(VERIFY_WRITE, uaddr, len);
if(err)
return err;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -