📄 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 intinet_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 intinet_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 intinet_dup(struct socket *newsock, struct socket *oldsock){ return(inet_create(newsock, ((struct sock *)(oldsock->data))->protocol));}/* The peer socket should always be NULL. */static intinet_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 intinet_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 intinet_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 intinet_socketpair(struct socket *sock1, struct socket *sock2){ return(-EOPNOTSUPP);}static intinet_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 intinet_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 + -