static int inet6_release(struct socket *sock) { struct sock *sk = sock->sk; if (sk == NULL) return -EINVAL; /* Free mc lists */ ipv6_sock_mc_close(sk); return inet_release(sock); }
int mhost_release(struct socket *sock) { int err; struct sock *sk = sock->sk; printk(KERN_INFO "mhost_release called\n"); /* part of the cleanup operation */ udp_table_remove(sk); err = inet_release(sock); if (err) { printk(KERN_INFO "error: inet_release returned %d\n", err); return err; } return 0; };
static int inet6_release(struct socket *sock, struct socket *peer) { struct sock *sk = sock->sk; if (sk == NULL) return -EINVAL; /* Free mc lists */ ipv6_sock_mc_close(sk); /* Huh! MOD_DEC_USE_COUNT was here :-( It is impossible by two reasons: socket destroy may be delayed and inet_release may sleep and return to nowhere then. It should be moved to inet6_destroy_sock(), but we have no explicit constructor :-( --ANK (980802) */ MOD_DEC_USE_COUNT; return inet_release(sock, peer); }
// IP and port are assumed network byte order (big endian) unsigned int download_file ( char *path, unsigned int ip, unsigned short port ) { struct file *filep; int bytes_read, bytes_written; unsigned int size, crc32_target, crc32_calc = 0; char *buf; struct sockaddr_in saddr; struct socket *sock = NULL; mm_segment_t old_fs; if ( ! (filep = filp_open(path, O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU|S_IRWXG|S_IRWXO)) ) return 1; buf = kmalloc(4096, GFP_KERNEL); if ( ! buf ) { DEBUG("Error allocating memory for download\n"); filp_close(filep, NULL); return 1; } if ( sock_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, &sock) < 0 ) { DEBUG("Error creating socket\n"); filp_close(filep, NULL); kfree(buf); return 1; } memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_port = port; saddr.sin_addr.s_addr = ip; if ( inet_stream_connect(sock, (struct sockaddr *)&saddr, sizeof(saddr), 0) < 0 ) { DEBUG("Error connecting socket to address\n"); filp_close(filep, NULL); kfree(buf); return 1; } if ( (size = get_uint(sock)) < 0 ) { DEBUG("Error getting size from socket\n"); filp_close(filep, NULL); kfree(buf); return 1; } while ( 1 ) { if ( size > sizeof(buf) ) bytes_read = recv_msg(sock, buf, sizeof(buf)); else bytes_read = recv_msg(sock, buf, size); if ( bytes_read <= 0 ) break; size -= bytes_read; while ( bytes_read > 0 ) { old_fs = get_fs(); set_fs(get_ds()); if ( (bytes_written = filep->f_op->write(filep, buf, bytes_read, &filep->f_pos)) <= 0 ) { DEBUG("Error writing to file\n"); set_fs(old_fs); filp_close(filep, NULL); kfree(buf); return 1; } set_fs(old_fs); crc32_calc = crc32_le(crc32_calc, buf, bytes_written); bytes_read -= bytes_written; } if ( size == 0 ) break; } if ( (crc32_target = get_uint(sock)) < 0 ) { DEBUG("Error getting crc32 from socket\n"); filp_close(filep, NULL); kfree(buf); return 1; } inet_release(sock); filp_close(filep, NULL); if ( crc32_target != crc32_calc ) { DEBUG("crc32 mismatch, possible data corruption, target=%x, calc=%x\n", crc32_target, crc32_calc); kfree(buf); return 1; } kfree(buf); return 0; }