📄 sock.c
字号:
/* Check this error. */
if (len < sizeof(sin)) return(-EINVAL);
sin.sin_family = AF_INET;
sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
}
if (peer) {
if (!tcp_connected(sk->state)) return(-ENOTCONN);
sin.sin_port = sk->dummy_th.dest;
sin.sin_addr.s_addr = sk->daddr;
} else {
sin.sin_port = sk->dummy_th.source;
if (sk->saddr == 0) sin.sin_addr.s_addr = my_addr();
else sin.sin_addr.s_addr = sk->saddr;
}
len = sizeof(sin);
/* verify_area(VERIFY_WRITE, uaddr, len); NOW DONE ABOVE */
memcpy_tofs(uaddr, &sin, sizeof(sin));
/* verify_area(VERIFY_WRITE, uaddr_len, sizeof(len)); NOW DONE ABOVE */
put_fs_long(len, uaddr_len);
return(0);
}
static int
inet_read(struct socket *sock, char *ubuf, int size, int noblock)
{
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);
}
return(sk->prot->read(sk, (unsigned char *) ubuf, size, noblock,0));
}
static int
inet_recv(struct socket *sock, void *ubuf, int size, int noblock,
unsigned flags)
{
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);
}
return(sk->prot->read(sk, (unsigned char *) ubuf, size, noblock, flags));
}
static int
inet_write(struct socket *sock, char *ubuf, int size, int noblock)
{
struct sock *sk;
sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
}
if (sk->shutdown & SEND_SHUTDOWN) {
send_sig(SIGPIPE, current, 1);
return(-EPIPE);
}
/* 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);
}
return(sk->prot->write(sk, (unsigned char *) ubuf, size, noblock, 0));
}
static int
inet_send(struct socket *sock, void *ubuf, int size, int noblock,
unsigned flags)
{
struct sock *sk;
sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
}
if (sk->shutdown & SEND_SHUTDOWN) {
send_sig(SIGPIPE, current, 1);
return(-EPIPE);
}
/* 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);
}
return(sk->prot->write(sk, (unsigned char *) ubuf, size, noblock, flags));
}
static int
inet_sendto(struct socket *sock, void *ubuf, int size, int noblock,
unsigned flags, struct sockaddr *sin, int addr_len)
{
struct sock *sk;
sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
}
if (sk->shutdown & SEND_SHUTDOWN) {
send_sig(SIGPIPE, current, 1);
return(-EPIPE);
}
if (sk->prot->sendto == NULL) return(-EOPNOTSUPP);
/* 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);
}
return(sk->prot->sendto(sk, (unsigned char *) ubuf, size, noblock, flags,
(struct sockaddr_in *)sin, addr_len));
}
static int
inet_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
unsigned flags, struct sockaddr *sin, int *addr_len )
{
struct sock *sk;
sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
}
if (sk->prot->recvfrom == NULL) return(-EOPNOTSUPP);
/* 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);
}
return(sk->prot->recvfrom(sk, (unsigned char *) ubuf, size, noblock, flags,
(struct sockaddr_in*)sin, addr_len));
}
static int
inet_shutdown(struct socket *sock, int how)
{
struct sock *sk;
/*
* This should really check to make sure
* the socket is a TCP socket.
*/
how++; /* maps 0->1 has the advantage of making bit 1 rcvs and
1->2 bit 2 snds.
2->3 */
if (how & ~SHUTDOWN_MASK) return(-EINVAL);
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;
if (!tcp_connected(sk->state)) return(-ENOTCONN);
sk->shutdown |= how;
if (sk->prot->shutdown) sk->prot->shutdown(sk, how);
return(0);
}
static int
inet_select(struct socket *sock, int sel_type, select_table *wait )
{
struct sock *sk;
sk = (struct sock *) sock->data;
if (sk == NULL) {
printk("Warning: sock->data = NULL: %d\n" ,__LINE__);
return(0);
}
if (sk->prot->select == NULL) {
DPRINTF((DBG_INET, "select on non-selectable socket.\n"));
return(0);
}
return(sk->prot->select(sk, sel_type, wait));
}
static int
inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk;
int err;
DPRINTF((DBG_INET, "INET: in inet_ioctl\n"));
sk = NULL;
if (sock && (sk = (struct sock *) sock->data) == NULL) {
printk("AF_INET: Warning: sock->data = NULL: %d\n" , __LINE__);
return(0);
}
switch(cmd) {
case FIOSETOWN:
case SIOCSPGRP:
err=verify_area(VERIFY_READ,(int *)arg,sizeof(long));
if(err)
return err;
if (sk)
sk->proc = get_fs_long((int *) arg);
return(0);
case FIOGETOWN:
case SIOCGPGRP:
if (sk) {
err=verify_area(VERIFY_WRITE,(void *) arg, sizeof(long));
if(err)
return err;
put_fs_long(sk->proc,(int *)arg);
}
return(0);
#if 0 /* FIXME: */
case SIOCATMARK:
printk("AF_INET: ioctl(SIOCATMARK, 0x%08X)\n",(void *) arg);
return(-EINVAL);
#endif
case DDIOCSDBG:
return(dbg_ioctl((void *) arg, DBG_INET));
case SIOCADDRT: case SIOCADDRTOLD:
case SIOCDELRT: case SIOCDELRTOLD:
return(rt_ioctl(cmd,(void *) arg));
case SIOCDARP:
case SIOCGARP:
case SIOCSARP:
return(arp_ioctl(cmd,(void *) arg));
case IP_SET_DEV:
case SIOCGIFCONF:
case SIOCGIFFLAGS:
case SIOCSIFFLAGS:
case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCGIFDSTADDR:
case SIOCSIFDSTADDR:
case SIOCGIFBRDADDR:
case SIOCSIFBRDADDR:
case SIOCGIFNETMASK:
case SIOCSIFNETMASK:
case SIOCGIFMETRIC:
case SIOCSIFMETRIC:
case SIOCGIFMEM:
case SIOCSIFMEM:
case SIOCGIFMTU:
case SIOCSIFMTU:
case SIOCSIFLINK:
case SIOCGIFHWADDR:
return(dev_ioctl(cmd,(void *) arg));
default:
if (!sk || !sk->prot->ioctl) return(-EINVAL);
return(sk->prot->ioctl(sk, cmd, arg));
}
/*NOTREACHED*/
return(0);
}
struct sk_buff *
sock_wmalloc(struct sock *sk, unsigned long size, int force,
int priority)
{
if (sk) {
if (sk->wmem_alloc + size < sk->sndbuf || force) {
struct sk_buff * c = alloc_skb(size, priority);
if (c) {
cli();
sk->wmem_alloc+= size;
sti();
}
return c;
}
DPRINTF((DBG_INET, "sock_wmalloc(%X,%d,%d,%d) returning NULL\n",
sk, size, force, priority));
return(NULL);
}
return(alloc_skb(size, priority));
}
struct sk_buff *
sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority)
{
if (sk) {
if (sk->rmem_alloc + size < sk->rcvbuf || force) {
struct sk_buff *c = alloc_skb(size, priority);
if (c) {
cli();
sk->rmem_alloc += size;
sti();
}
return(c);
}
DPRINTF((DBG_INET, "sock_rmalloc(%X,%d,%d,%d) returning NULL\n",
sk,size,force, priority));
return(NULL);
}
return(alloc_skb(size, priority));
}
unsigned long
sock_rspace(struct sock *sk)
{
int amt;
if (sk != NULL) {
if (sk->rmem_alloc >= sk->rcvbuf-2*MIN_WINDOW) return(0);
amt = min((sk->rcvbuf-sk->rmem_alloc)/2-MIN_WINDOW, MAX_WINDOW);
if (amt < 0) return(0);
return(amt);
}
return(0);
}
unsigned long
sock_wspace(struct sock *sk)
{
if (sk != NULL) {
if (sk->shutdown & SEND_SHUTDOWN) return(0);
if (sk->wmem_alloc >= sk->sndbuf) return(0);
return(sk->sndbuf-sk->wmem_alloc );
}
return(0);
}
void
sock_wfree(struct sock *sk, void *mem, unsigned long size)
{
DPRINTF((DBG_INET, "sock_wfree(sk=%X, mem=%X, size=%d)\n", sk, mem, size));
IS_SKB(mem);
kfree_skbmem(mem, size);
if (sk) {
sk->wmem_alloc -= size;
/* In case it might be waiting for more memory. */
if (!sk->dead) sk->write_space(sk);
if (sk->destroy && sk->wmem_alloc == 0 && sk->rmem_alloc == 0) {
DPRINTF((DBG_INET,
"recovered lost memory, sock = %X\n", sk));
}
return;
}
}
void
sock_rfree(struct sock *sk, void *mem, unsigned long size)
{
DPRINTF((DBG_INET, "sock_rfree(sk=%X, mem=%X, size=%d)\n", sk, mem, size));
IS_SKB(mem);
kfree_skbmem(mem, size);
if (sk) {
sk->rmem_alloc -= size;
if (sk->destroy && sk->wmem_alloc == 0 && sk->rmem_alloc == 0) {
DPRINTF((DBG_INET,
"recovered lot memory, sock = %X\n", sk));
}
}
}
/*
* This routine must find a socket given a TCP or UDP header.
* Everyhting is assumed to be in net order.
*/
struct sock *get_sock(struct proto *prot, unsigned short num,
unsigned long raddr,
unsigned short rnum, unsigned long laddr)
{
struct sock *s;
unsigned short hnum;
hnum = ntohs(num);
DPRINTF((DBG_INET, "get_sock(prot=%X, num=%d, raddr=%X, rnum=%d, laddr=%X)\n",
prot, num, raddr, rnum, laddr));
/*
* SOCK_ARRAY_SIZE must be a power of two. This will work better
* than a prime unless 3 or more sockets end up using the same
* array entry. This should not be a problem because most
* well known sockets don't overlap that much, and for
* the other ones, we can just be careful about picking our
* socket number when we choose an arbitrary one.
*/
for(s = prot->sock_array[hnum & (SOCK_ARRAY_SIZE - 1)];
s != NULL; s = s->next)
{
if (s->num != hnum)
continue;
if(s->dead && (s->state == TCP_CLOSE))
continue;
if(prot == &udp_prot)
return s;
if(ip_addr_match(s->daddr,raddr)==0)
continue;
if (s->dummy_th.dest != rnum && s->dummy_th.dest != 0)
continue;
if(ip_addr_match(s->saddr,laddr) == 0)
continue;
return(s);
}
return(NULL);
}
void release_sock(struct sock *sk)
{
if (!sk) {
printk("sock.c: release_sock sk == NULL\n");
return;
}
if (!sk->prot) {
/* printk("sock.c: release_sock sk->prot == NULL\n"); */
return;
}
if (sk->blog) return;
/* See if we have any packets built up. */
cli();
sk->inuse = 1;
while(sk->back_log != NULL) {
struct sk_buff *skb;
sk->blog = 1;
skb =(struct sk_buff *)sk->back_log;
DPRINTF((DBG_INET, "release_sock: skb = %X:\n", skb));
if (skb->next != skb) {
sk->back_log = skb->next;
skb->prev->next = skb->next;
skb->next->prev = skb->prev;
} else {
sk->back_log = NULL;
}
sti();
DPRINTF((DBG_INET, "sk->back_log = %X\n", sk->back_log));
if (sk->prot->rcv) sk->prot->rcv(skb, skb->dev, sk->opt,
skb->saddr, skb->len, skb->daddr, 1,
/* Only used for/by raw sockets. */
(struct inet_protocol *)sk->pair);
cli();
}
sk->blog = 0;
sk->inuse = 0;
sti();
if (sk->dead && sk->state == TCP_CLOSE) {
/* Should be about 2 rtt's */
reset_timer(sk, TIME_DONE, min(sk->rtt * 2, TCP_DONE_TIME));
}
}
static int
inet_fioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int minor, ret;
/* Extract the minor number on which we work. */
minor = MINOR(inode->i_rdev);
if (minor != 0) return(-ENODEV);
/* Now dispatch on the minor device. */
switch(minor) {
case 0: /* INET */
ret = inet_ioctl(NULL, cmd, arg);
break;
case 1: /* IP */
ret = ip_ioctl(NULL, cmd, arg);
break;
case 2: /* ICMP */
ret = icmp_ioctl(NULL, cmd, arg);
break;
case 3: /* TCP */
ret = tcp_ioctl(NULL, cmd, arg);
break;
case 4: /* UDP */
ret = udp_ioctl(NULL, cmd, arg);
break;
default:
ret = -ENODEV;
}
return(ret);
}
static struct file_operations inet_fops = {
NULL, /* LSEEK */
NULL, /* READ */
NULL, /* WRITE */
NULL, /* READDIR */
NULL, /* SELECT */
inet_fioctl, /* IOCTL */
NULL, /* MMAP */
NULL, /* OPEN */
NULL /* CLOSE */
};
static struct proto_ops inet_proto_ops = {
AF_INET,
inet_create,
inet_dup,
inet_release,
inet_bind,
inet_connect,
inet_socketpair,
inet_accept,
inet_getname,
inet_read,
inet_write,
inet_select,
inet_ioctl,
inet_listen,
inet_send,
inet_recv,
inet_sendto,
inet_recvfrom,
inet_shutdown,
inet_setsockopt,
inet_getsockopt,
inet_fcntl,
};
extern unsigned long seq_offset;
/* Called by ddi.c on kernel startup. */
void inet_proto_init(struct ddi_proto *pro)
{
struct inet_protocol *p;
int i;
printk("Swansea University Computer Society Net2Debugged [1.30]\n");
/* Set up our UNIX VFS major device. */
if (register_chrdev(AF_INET_MAJOR, "af_inet", &inet_fops) < 0) {
printk("%s: cannot register major device %d!\n",
pro->name, AF_INET_MAJOR);
return;
}
/* Tell SOCKET that we are alive... */
(void) sock_register(inet_proto_ops.family, &inet_proto_ops);
seq_offset = CURRENT_TIME*250;
/* Add all the protocols. */
for(i = 0; i < SOCK_ARRAY_SIZE; i++) {
tcp_prot.sock_array[i] = NULL;
udp_prot.sock_array[i] = NULL;
raw_prot.sock_array[i] = NULL;
}
printk("IP Protocols: ");
for(p = inet_protocol_base; p != NULL;) {
struct inet_protocol *tmp;
tmp = (struct inet_protocol *) p->next;
inet_add_protocol(p);
printk("%s%s",p->name,tmp?", ":"\n");
p = tmp;
}
/* Initialize the DEV module. */
dev_init();
/* Initialize the "Buffer Head" pointers. */
bh_base[INET_BH].routine = inet_bh;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -