/* * @(#) RFC2367 PF_KEYv2 Key management API domain socket I/F * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See . * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * RCSID $Id: pfkey_v2.c,v 1.4 2004/09/29 22:27:41 as Exp $ */ /* * Template from /usr/src/linux-2.0.36/net/unix/af_unix.c. * Hints from /usr/src/linux-2.0.36/net/ipv4/udp.c. */ #define __NO_VERSION__ #include #include #include #include #include "freeswan/ipsec_param.h" #include #include #include #include #include #include #include #include #include #include #include #include #include /* struct socket */ #include #include #ifdef MALLOC_SLAB # include /* kmalloc() */ #else /* MALLOC_SLAB */ # include /* kmalloc() */ #endif /* MALLOC_SLAB */ #include #include #include #include /* struct sock */ /* #include */ #include #ifdef CONFIG_PROC_FS # include #endif /* CONFIG_PROC_FS */ #include #include #ifdef NET_21 # include # include #endif /* NET_21 */ #include "freeswan/radij.h" #include "freeswan/ipsec_encap.h" #include "freeswan/ipsec_sa.h" #include #include #include "freeswan/ipsec_proto.h" #ifdef CONFIG_IPSEC_DEBUG int debug_pfkey = 0; extern int sysctl_ipsec_debug_verbose; #endif /* CONFIG_IPSEC_DEBUG */ #define SENDERR(_x) do { error = -(_x); goto errlab; } while (0) #ifndef SOCKOPS_WRAPPED #define SOCKOPS_WRAPPED(name) name #endif /* SOCKOPS_WRAPPED */ extern struct proto_ops pfkey_ops; struct sock *pfkey_sock_list = NULL; struct supported_list *pfkey_supported_list[SADB_SATYPE_MAX+1]; struct socket_list *pfkey_open_sockets = NULL; struct socket_list *pfkey_registered_sockets[SADB_SATYPE_MAX+1]; int pfkey_msg_interp(struct sock *, struct sadb_msg *, struct sadb_msg **); int pfkey_list_remove_socket(struct socket *socketp, struct socket_list **sockets) { struct socket_list *socket_listp,*prev; if(!socketp) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_list_remove_socket: " "NULL socketp handed in, failed.\n"); return -EINVAL; } if(!sockets) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_list_remove_socket: " "NULL sockets list handed in, failed.\n"); return -EINVAL; } socket_listp = *sockets; prev = NULL; KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_list_remove_socket: " "removing sock=0p%p\n", socketp); while(socket_listp != NULL) { if(socket_listp->socketp == socketp) { if(prev != NULL) { prev->next = socket_listp->next; } else { *sockets = socket_listp->next; } kfree((void*)socket_listp); break; } prev = socket_listp; socket_listp = socket_listp->next; } return 0; } int pfkey_list_insert_socket(struct socket *socketp, struct socket_list **sockets) { struct socket_list *socket_listp; if(!socketp) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_list_insert_socket: " "NULL socketp handed in, failed.\n"); return -EINVAL; } if(!sockets) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_list_insert_socket: " "NULL sockets list handed in, failed.\n"); return -EINVAL; } KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_list_insert_socket: " "allocating %lu bytes for socketp=0p%p\n", (unsigned long) sizeof(struct socket_list), socketp); if((socket_listp = (struct socket_list *)kmalloc(sizeof(struct socket_list), GFP_KERNEL)) == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_list_insert_socket: " "memory allocation error.\n"); return -ENOMEM; } socket_listp->socketp = socketp; socket_listp->next = *sockets; *sockets = socket_listp; return 0; } int pfkey_list_remove_supported(struct supported *supported, struct supported_list **supported_list) { struct supported_list *supported_listp = *supported_list, *prev = NULL; if(!supported) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_list_remove_supported: " "NULL supported handed in, failed.\n"); return -EINVAL; } if(!supported_list) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_list_remove_supported: " "NULL supported_list handed in, failed.\n"); return -EINVAL; } KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_list_remove_supported: " "removing supported=0p%p\n", supported); while(supported_listp != NULL) { if(supported_listp->supportedp == supported) { if(prev != NULL) { prev->next = supported_listp->next; } else { *supported_list = supported_listp->next; } kfree((void*)supported_listp); break; } prev = supported_listp; supported_listp = supported_listp->next; } return 0; } int pfkey_list_insert_supported(struct supported *supported, struct supported_list **supported_list) { struct supported_list *supported_listp; if(!supported) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_list_insert_supported: " "NULL supported handed in, failed.\n"); return -EINVAL; } if(!supported_list) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_list_insert_supported: " "NULL supported_list handed in, failed.\n"); return -EINVAL; } KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_list_insert_supported: " "allocating %lu bytes for incoming, supported=0p%p, supported_list=0p%p\n", (unsigned long) sizeof(struct supported_list), supported, supported_list); supported_listp = (struct supported_list *)kmalloc(sizeof(struct supported_list), GFP_KERNEL); if(supported_listp == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_list_insert_supported: " "memory allocation error.\n"); return -ENOMEM; } supported_listp->supportedp = supported; supported_listp->next = *supported_list; *supported_list = supported_listp; KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_list_insert_supported: " "outgoing, supported=0p%p, supported_list=0p%p\n", supported, supported_list); return 0; } #ifndef NET_21 DEBUG_NO_STATIC void pfkey_state_change(struct sock *sk) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_state_change: .\n"); if(!sk->dead) { wake_up_interruptible(sk->sleep); } } #endif /* !NET_21 */ #ifndef NET_21 DEBUG_NO_STATIC void pfkey_data_ready(struct sock *sk, int len) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_data_ready: " "sk=0p%p len=%d\n", sk, len); if(!sk->dead) { wake_up_interruptible(sk->sleep); sock_wake_async(sk->socket, 1); } } DEBUG_NO_STATIC void pfkey_write_space(struct sock *sk) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_write_space: .\n"); if(!sk->dead) { wake_up_interruptible(sk->sleep); sock_wake_async(sk->socket, 2); } } #endif /* !NET_21 */ DEBUG_NO_STATIC void pfkey_insert_socket(struct sock *sk) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_insert_socket: " "sk=0p%p\n", sk); cli(); sk->next=pfkey_sock_list; pfkey_sock_list=sk; sti(); } DEBUG_NO_STATIC void pfkey_remove_socket(struct sock *sk) { struct sock **s; KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_remove_socket: .\n"); cli(); s=&pfkey_sock_list; while(*s!=NULL) { if(*s==sk) { *s=sk->next; sk->next=NULL; sti(); KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_remove_socket: " "succeeded.\n"); return; } s=&((*s)->next); } sti(); KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_remove_socket: " "not found.\n"); return; } DEBUG_NO_STATIC void pfkey_destroy_socket(struct sock *sk) { struct sk_buff *skb; KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_destroy_socket: .\n"); pfkey_remove_socket(sk); KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_destroy_socket: " "pfkey_remove_socket called.\n"); KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_destroy_socket: " "sk(0p%p)->(&0p%p)receive_queue.{next=0p%p,prev=0p%p}.\n", sk, &(sk->receive_queue), sk->receive_queue.next, sk->receive_queue.prev); while(sk && ((skb=skb_dequeue(&(sk->receive_queue)))!=NULL)) { #ifdef NET_21 #ifdef CONFIG_IPSEC_DEBUG if(debug_pfkey && sysctl_ipsec_debug_verbose) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_destroy_socket: " "skb=0p%p dequeued.\n", skb); printk(KERN_INFO "klips_debug:pfkey_destroy_socket: " "pfkey_skb contents:"); printk(" next:0p%p", skb->next); printk(" prev:0p%p", skb->prev); printk(" list:0p%p", skb->list); printk(" sk:0p%p", skb->sk); printk(" stamp:%ld.%ld", skb->stamp.tv_sec, skb->stamp.tv_usec); printk(" dev:0p%p", skb->dev); if(skb->dev) { if(skb->dev->name) { printk(" dev->name:%s", skb->dev->name); } else { printk(" dev->name:NULL?"); } } else { printk(" dev:NULL"); } printk(" h:0p%p", skb->h.raw); printk(" nh:0p%p", skb->nh.raw); printk(" mac:0p%p", skb->mac.raw); printk(" dst:0p%p", skb->dst); if(sysctl_ipsec_debug_verbose) { int i; printk(" cb"); for(i=0; i<48; i++) { printk(":%2x", skb->cb[i]); } } printk(" len:%d", skb->len); printk(" csum:%d", skb->csum); #ifndef NETDEV_23 printk(" used:%d", skb->used); printk(" is_clone:%d", skb->is_clone); #endif /* NETDEV_23 */ printk(" cloned:%d", skb->cloned); printk(" pkt_type:%d", skb->pkt_type); printk(" ip_summed:%d", skb->ip_summed); printk(" priority:%d", skb->priority); printk(" protocol:%d", skb->protocol); printk(" security:%d", skb->security); printk(" truesize:%d", skb->truesize); printk(" head:0p%p", skb->head); printk(" data:0p%p", skb->data); printk(" tail:0p%p", skb->tail); printk(" end:0p%p", skb->end); if(sysctl_ipsec_debug_verbose) { unsigned char* i; printk(" data"); for(i = skb->head; i < skb->end; i++) { printk(":%2x", (unsigned char)(*(i))); } } printk(" destructor:0p%p", skb->destructor); printk("\n"); } #endif /* CONFIG_IPSEC_DEBUG */ #endif /* NET_21 */ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_destroy_socket: " "skb=0p%p freed.\n", skb); ipsec_kfree_skb(skb); } sk->dead = 1; sk_free(sk); KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_destroy_socket: destroyed.\n"); } int pfkey_upmsg(struct socket *sock, struct sadb_msg *pfkey_msg) { int error = 0; struct sk_buff * skb = NULL; struct sock *sk; if(sock == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_upmsg: " "NULL socket passed in.\n"); return -EINVAL; } if(pfkey_msg == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_upmsg: " "NULL pfkey_msg passed in.\n"); return -EINVAL; } #ifdef NET_21 sk = sock->sk; #else /* NET_21 */ sk = sock->data; #endif /* NET_21 */ if(sk == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_upmsg: " "NULL sock passed in.\n"); return -EINVAL; } KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_upmsg: " "allocating %d bytes...\n", (int)(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN)); if(!(skb = alloc_skb(pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN, GFP_ATOMIC) )) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_upmsg: " "no buffers left to send up a message.\n"); return -ENOBUFS; } KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_upmsg: " "...allocated at 0p%p.\n", skb); skb->dev = NULL; if(skb_tailroom(skb) < pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN) { printk(KERN_WARNING "klips_error:pfkey_upmsg: " "tried to skb_put %ld, %d available. This should never happen, please report.\n", (unsigned long int)pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN, skb_tailroom(skb)); ipsec_kfree_skb(skb); return -ENOBUFS; } skb->h.raw = skb_put(skb, pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN); memcpy(skb->h.raw, pfkey_msg, pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN); #ifndef NET_21 skb->free = 1; #endif /* !NET_21 */ if((error = sock_queue_rcv_skb(sk, skb)) < 0) { skb->sk=NULL; KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_upmsg: " "error=%d calling sock_queue_rcv_skb with skb=0p%p.\n", error, skb); ipsec_kfree_skb(skb); return error; } return error; } DEBUG_NO_STATIC int pfkey_create(struct socket *sock, int protocol) { struct sock *sk; if(sock == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_create: " "socket NULL.\n"); return -EINVAL; } KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_create: " "sock=0p%p type:%d state:%d flags:%ld protocol:%d\n", sock, sock->type, (unsigned int)(sock->state), sock->flags, protocol); if(sock->type != SOCK_RAW) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_create: " "only SOCK_RAW supported.\n"); return -ESOCKTNOSUPPORT; } if(protocol != PF_KEY_V2) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_create: " "protocol not PF_KEY_V2.\n"); return -EPROTONOSUPPORT; } if((current->uid != 0)) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_create: " "must be root to open pfkey sockets.\n"); return -EACCES; } #ifdef NET_21 sock->state = SS_UNCONNECTED; #endif /* NET_21 */ MOD_INC_USE_COUNT; #ifdef NET_21 if((sk=(struct sock *)sk_alloc(PF_KEY, GFP_KERNEL, 1)) == NULL) #else /* NET_21 */ if((sk=(struct sock *)sk_alloc(GFP_KERNEL)) == NULL) #endif /* NET_21 */ { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_create: " "Out of memory trying to allocate.\n"); MOD_DEC_USE_COUNT; return -ENOMEM; } #ifndef NET_21 memset(sk, 0, sizeof(*sk)); #endif /* !NET_21 */ #ifdef NET_21 sock_init_data(sock, sk); sk->destruct = NULL; sk->reuse = 1; sock->ops = &pfkey_ops; sk->zapped=0; sk->family = PF_KEY; /* sk->num = protocol; */ sk->protocol = protocol; key_pid(sk) = current->pid; KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_create: " "sock->fasync_list=0p%p sk->sleep=0p%p.\n", sock->fasync_list, sk->sleep); #else /* NET_21 */ sk->type=sock->type; init_timer(&sk->timer); skb_queue_head_init(&sk->write_queue); skb_queue_head_init(&sk->receive_queue); skb_queue_head_init(&sk->back_log); sk->rcvbuf=SK_RMEM_MAX; sk->sndbuf=SK_WMEM_MAX; sk->allocation=GFP_KERNEL; sk->state=TCP_CLOSE; sk->priority=SOPRI_NORMAL; sk->state_change=pfkey_state_change; sk->data_ready=pfkey_data_ready; sk->write_space=pfkey_write_space; sk->error_report=pfkey_state_change; sk->mtu=4096; sk->socket=sock; sock->data=(void *)sk; sk->sleep=sock->wait; #endif /* NET_21 */ pfkey_insert_socket(sk); pfkey_list_insert_socket(sock, &pfkey_open_sockets); KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_create: " "Socket sock=0p%p sk=0p%p initialised.\n", sock, sk); return 0; } #ifndef NET_21 DEBUG_NO_STATIC int pfkey_dup(struct socket *newsock, struct socket *oldsock) { struct sock *sk; if(newsock==NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_dup: " "No new socket attached.\n"); return -EINVAL; } if(oldsock==NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_dup: " "No old socket attached.\n"); return -EINVAL; } #ifdef NET_21 sk=oldsock->sk; #else /* NET_21 */ sk=oldsock->data; #endif /* NET_21 */ /* May not have data attached */ if(sk==NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_dup: " "No sock attached to old socket.\n"); return -EINVAL; } KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_dup: .\n"); return pfkey_create(newsock, sk->protocol); } #endif /* !NET_21 */ DEBUG_NO_STATIC int #ifdef NETDEV_23 pfkey_release(struct socket *sock) #else /* NETDEV_23 */ pfkey_release(struct socket *sock, struct socket *peersock) #endif /* NETDEV_23 */ { struct sock *sk; int i; if(sock==NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_release: " "No socket attached.\n"); return 0; /* -EINVAL; */ } #ifdef NET_21 sk=sock->sk; #else /* NET_21 */ sk=sock->data; #endif /* NET_21 */ /* May not have data attached */ if(sk==NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_release: " "No sk attached to sock=0p%p.\n", sock); return 0; /* -EINVAL; */ } KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_release: " "sock=0p%p sk=0p%p\n", sock, sk); #ifdef NET_21 if(!sk->dead) #endif /* NET_21 */ if(sk->state_change) { sk->state_change(sk); } #ifdef NET_21 sock->sk = NULL; #else /* NET_21 */ sock->data = NULL; #endif /* NET_21 */ /* Try to flush out this socket. Throw out buffers at least */ pfkey_destroy_socket(sk); pfkey_list_remove_socket(sock, &pfkey_open_sockets); for(i = SADB_SATYPE_UNSPEC; i <= SADB_SATYPE_MAX; i++) { pfkey_list_remove_socket(sock, &(pfkey_registered_sockets[i])); } MOD_DEC_USE_COUNT; KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_release: " "succeeded.\n"); return 0; } #ifndef NET_21 DEBUG_NO_STATIC int pfkey_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_bind: " "operation not supported.\n"); return -EINVAL; } DEBUG_NO_STATIC int pfkey_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_connect: " "operation not supported.\n"); return -EINVAL; } DEBUG_NO_STATIC int pfkey_socketpair(struct socket *a, struct socket *b) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_socketpair: " "operation not supported.\n"); return -EINVAL; } DEBUG_NO_STATIC int pfkey_accept(struct socket *sock, struct socket *newsock, int flags) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_aaccept: " "operation not supported.\n"); return -EINVAL; } DEBUG_NO_STATIC int pfkey_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { struct sockaddr *ska = (struct sockaddr*)uaddr; KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getname: .\n"); ska->sa_family = PF_KEY; *uaddr_len = sizeof(*ska); return 0; } DEBUG_NO_STATIC int pfkey_select(struct socket *sock, int sel_type, select_table *wait) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_select: " ".sock=0p%p sk=0p%p sel_type=%d\n", sock, sock->data, sel_type); if(sock == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_select: " "Null socket passed in.\n"); return -EINVAL; } return datagram_select(sock->data, sel_type, wait); } DEBUG_NO_STATIC int pfkey_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_ioctl: " "not supported.\n"); return -EINVAL; } DEBUG_NO_STATIC int pfkey_listen(struct socket *sock, int backlog) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_listen: " "not supported.\n"); return -EINVAL; } #endif /* !NET_21 */ DEBUG_NO_STATIC int pfkey_shutdown(struct socket *sock, int mode) { struct sock *sk; if(sock == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_shutdown: " "NULL socket passed in.\n"); return -EINVAL; } #ifdef NET_21 sk=sock->sk; #else /* NET_21 */ sk=sock->data; #endif /* NET_21 */ if(sk == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_shutdown: " "No sock attached to socket.\n"); return -EINVAL; } KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_shutdown: " "mode=%x.\n", mode); mode++; if(mode&SEND_SHUTDOWN) { sk->shutdown|=SEND_SHUTDOWN; sk->state_change(sk); } if(mode&RCV_SHUTDOWN) { sk->shutdown|=RCV_SHUTDOWN; sk->state_change(sk); } return 0; } #ifndef NET_21 DEBUG_NO_STATIC int pfkey_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) { #ifndef NET_21 struct sock *sk; if(sock == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_setsockopt: " "Null socket passed in.\n"); return -EINVAL; } sk=sock->data; if(sk == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_setsockopt: " "Null sock passed in.\n"); return -EINVAL; } #endif /* !NET_21 */ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_setsockopt: .\n"); if(level!=SOL_SOCKET) { return -EOPNOTSUPP; } #ifdef NET_21 return sock_setsockopt(sock, level, optname, optval, optlen); #else /* NET_21 */ return sock_setsockopt(sk, level, optname, optval, optlen); #endif /* NET_21 */ } DEBUG_NO_STATIC int pfkey_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) { #ifndef NET_21 struct sock *sk; if(sock == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_setsockopt: " "Null socket passed in.\n"); return -EINVAL; } sk=sock->data; if(sk == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_setsockopt: " "Null sock passed in.\n"); return -EINVAL; } #endif /* !NET_21 */ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_getsockopt: .\n"); if(level!=SOL_SOCKET) { return -EOPNOTSUPP; } #ifdef NET_21 return sock_getsockopt(sock, level, optname, optval, optlen); #else /* NET_21 */ return sock_getsockopt(sk, level, optname, optval, optlen); #endif /* NET_21 */ } DEBUG_NO_STATIC int pfkey_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_fcntl: " "not supported.\n"); return -EINVAL; } #endif /* !NET_21 */ /* * Send PF_KEY data down. */ DEBUG_NO_STATIC int #ifdef NET_21 pfkey_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) #else /* NET_21 */ pfkey_sendmsg(struct socket *sock, struct msghdr *msg, int len, int nonblock, int flags) #endif /* NET_21 */ { struct sock *sk; int error = 0; struct sadb_msg *pfkey_msg = NULL, *pfkey_reply = NULL; if(sock == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "Null socket passed in.\n"); SENDERR(EINVAL); } #ifdef NET_21 sk = sock->sk; #else /* NET_21 */ sk = sock->data; #endif /* NET_21 */ if(sk == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "Null sock passed in.\n"); SENDERR(EINVAL); } if(msg == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "Null msghdr passed in.\n"); SENDERR(EINVAL); } KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: .\n"); if(sk->err) { error = sock_error(sk); KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "sk->err is non-zero, returns %d.\n", error); SENDERR(-error); } if((current->uid != 0)) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "must be root to send messages to pfkey sockets.\n"); SENDERR(EACCES); } #ifdef NET_21 if(msg->msg_control) #else /* NET_21 */ if(flags || msg->msg_control) #endif /* NET_21 */ { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "can't set flags or set msg_control.\n"); SENDERR(EINVAL); } if(sk->shutdown & SEND_SHUTDOWN) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "shutdown.\n"); send_sig(SIGPIPE, current, 0); SENDERR(EPIPE); } if(len < sizeof(struct sadb_msg)) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "bogus msg len of %d, too small.\n", len); SENDERR(EMSGSIZE); } KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "allocating %d bytes for downward message.\n", len); if((pfkey_msg = (struct sadb_msg*)kmalloc(len, GFP_KERNEL)) == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "memory allocation error.\n"); SENDERR(ENOBUFS); } memcpy_fromiovec((void *)pfkey_msg, msg->msg_iov, len); if(pfkey_msg->sadb_msg_version != PF_KEY_V2) { KLIPS_PRINT(1 || debug_pfkey, "klips_debug:pfkey_sendmsg: " "not PF_KEY_V2 msg, found %d, should be %d.\n", pfkey_msg->sadb_msg_version, PF_KEY_V2); kfree((void*)pfkey_msg); return -EINVAL; } if(len != pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "bogus msg len of %d, not %d byte aligned.\n", len, (int)IPSEC_PFKEYv2_ALIGN); SENDERR(EMSGSIZE); } #if 0 /* This check is questionable, since a downward message could be the result of an ACQUIRE either from kernel (PID==0) or userspace (some other PID). */ /* check PID */ if(pfkey_msg->sadb_msg_pid != current->pid) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "pid (%d) does not equal sending process pid (%d).\n", pfkey_msg->sadb_msg_pid, current->pid); SENDERR(EINVAL); } #endif if(pfkey_msg->sadb_msg_reserved) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "reserved field must be zero, set to %d.\n", pfkey_msg->sadb_msg_reserved); SENDERR(EINVAL); } if((pfkey_msg->sadb_msg_type > SADB_MAX) || (!pfkey_msg->sadb_msg_type)){ KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "msg type too large or small:%d.\n", pfkey_msg->sadb_msg_type); SENDERR(EINVAL); } KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "msg sent for parsing.\n"); if((error = pfkey_msg_interp(sk, pfkey_msg, &pfkey_reply))) { struct socket_list *pfkey_socketsp; KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "pfkey_msg_parse returns %d.\n", error); if((pfkey_reply = (struct sadb_msg*)kmalloc(sizeof(struct sadb_msg), GFP_KERNEL)) == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "memory allocation error.\n"); SENDERR(ENOBUFS); } memcpy((void*)pfkey_reply, (void*)pfkey_msg, sizeof(struct sadb_msg)); pfkey_reply->sadb_msg_errno = -error; pfkey_reply->sadb_msg_len = sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN; for(pfkey_socketsp = pfkey_open_sockets; pfkey_socketsp; pfkey_socketsp = pfkey_socketsp->next) { int error_upmsg = 0; KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "sending up error=%d message=0p%p to socket=0p%p.\n", error, pfkey_reply, pfkey_socketsp->socketp); if((error_upmsg = pfkey_upmsg(pfkey_socketsp->socketp, pfkey_reply))) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "sending up error message to socket=0p%p failed with error=%d.\n", pfkey_socketsp->socketp, error_upmsg); /* pfkey_msg_free(&pfkey_reply); */ /* SENDERR(-error); */ } KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "sending up error message to socket=0p%p succeeded.\n", pfkey_socketsp->socketp); } pfkey_msg_free(&pfkey_reply); SENDERR(-error); } errlab: if (pfkey_msg) { kfree((void*)pfkey_msg); } if(error) { return error; } else { return len; } } /* * Receive PF_KEY data up. */ DEBUG_NO_STATIC int #ifdef NET_21 pfkey_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm) #else /* NET_21 */ pfkey_recvmsg(struct socket *sock, struct msghdr *msg, int size, int noblock, int flags, int *addr_len) #endif /* NET_21 */ { struct sock *sk; #ifdef NET_21 int noblock = flags & MSG_DONTWAIT; #endif /* NET_21 */ struct sk_buff *skb; int error; if(sock == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_recvmsg: " "Null socket passed in.\n"); return -EINVAL; } #ifdef NET_21 sk = sock->sk; #else /* NET_21 */ sk = sock->data; #endif /* NET_21 */ if(sk == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_recvmsg: " "Null sock passed in for sock=0p%p.\n", sock); return -EINVAL; } if(msg == NULL) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_recvmsg: " "Null msghdr passed in for sock=0p%p, sk=0p%p.\n", sock, sk); return -EINVAL; } KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose, "klips_debug:pfkey_recvmsg: sock=0p%p sk=0p%p msg=0p%p size=%d.\n", sock, sk, msg, size); if(flags & ~MSG_PEEK) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "flags (%d) other than MSG_PEEK not supported.\n", flags); return -EOPNOTSUPP; } #ifdef NET_21 msg->msg_namelen = 0; /* sizeof(*ska); */ #else /* NET_21 */ if(addr_len) { *addr_len = 0; /* sizeof(*ska); */ } #endif /* NET_21 */ if(sk->err) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_sendmsg: " "sk->err=%d.\n", sk->err); return sock_error(sk); } if((skb = skb_recv_datagram(sk, flags, noblock, &error) ) == NULL) { return error; } if(size > skb->len) { size = skb->len; } #ifdef NET_21 else if(size len) { msg->msg_flags |= MSG_TRUNC; } #endif /* NET_21 */ skb_copy_datagram_iovec(skb, 0, msg->msg_iov, size); sk->stamp=skb->stamp; skb_free_datagram(sk, skb); return size; } #ifdef NET_21 struct net_proto_family pfkey_family_ops = { PF_KEY, pfkey_create }; struct proto_ops SOCKOPS_WRAPPED(pfkey_ops) = { #ifdef NETDEV_23 family: PF_KEY, release: pfkey_release, bind: sock_no_bind, connect: sock_no_connect, socketpair: sock_no_socketpair, accept: sock_no_accept, getname: sock_no_getname, poll: datagram_poll, ioctl: sock_no_ioctl, listen: sock_no_listen, shutdown: pfkey_shutdown, setsockopt: sock_no_setsockopt, getsockopt: sock_no_getsockopt, sendmsg: pfkey_sendmsg, recvmsg: pfkey_recvmsg, mmap: sock_no_mmap, #else /* NETDEV_23 */ PF_KEY, sock_no_dup, pfkey_release, sock_no_bind, sock_no_connect, sock_no_socketpair, sock_no_accept, sock_no_getname, datagram_poll, sock_no_ioctl, sock_no_listen, pfkey_shutdown, sock_no_setsockopt, sock_no_getsockopt, sock_no_fcntl, pfkey_sendmsg, pfkey_recvmsg #endif /* NETDEV_23 */ }; #ifdef NETDEV_23 #include SOCKOPS_WRAP(pfkey, PF_KEY); #endif /* NETDEV_23 */ #else /* NET_21 */ struct proto_ops pfkey_proto_ops = { PF_KEY, pfkey_create, pfkey_dup, pfkey_release, pfkey_bind, pfkey_connect, pfkey_socketpair, pfkey_accept, pfkey_getname, pfkey_select, pfkey_ioctl, pfkey_listen, pfkey_shutdown, pfkey_setsockopt, pfkey_getsockopt, pfkey_fcntl, pfkey_sendmsg, pfkey_recvmsg }; #endif /* NET_21 */ #ifdef CONFIG_PROC_FS #ifndef PROC_FS_2325 DEBUG_NO_STATIC #endif /* PROC_FS_2325 */ int pfkey_get_info(char *buffer, char **start, off_t offset, int length #ifndef PROC_NO_DUMMY , int dummy #endif /* !PROC_NO_DUMMY */ ) { const int max_content = length > 0? length-1 : 0; off_t begin=0; int len=0; struct sock *sk=pfkey_sock_list; #ifdef CONFIG_IPSEC_DEBUG if(!sysctl_ipsec_debug_verbose) { #endif /* CONFIG_IPSEC_DEBUG */ len+= snprintf(buffer,length, " sock pid socket next prev e n p sndbf Flags Type St\n"); #ifdef CONFIG_IPSEC_DEBUG } else { len+= snprintf(buffer,length, " sock pid d sleep socket next prev e r z n p sndbf stamp Flags Type St\n"); } #endif /* CONFIG_IPSEC_DEBUG */ while(sk!=NULL) { #ifdef CONFIG_IPSEC_DEBUG if(!sysctl_ipsec_debug_verbose) { #endif /* CONFIG_IPSEC_DEBUG */ len += ipsec_snprintf(buffer+len, length-len, "%8p %5d %8p %8p %8p %d %d %d %5d %08lX %8X %2X\n", sk, key_pid(sk), sk->socket, sk->next, sk->prev, sk->err, sk->num, sk->protocol, sk->sndbuf, sk->socket->flags, sk->socket->type, sk->socket->state); #ifdef CONFIG_IPSEC_DEBUG } else { len += ipsec_snprintf(buffer+len, length-len, "%8p %5d %d %8p %8p %8p %8p %d %d %d %d %d %5d %d.%06d %08lX %8X %2X\n", sk, key_pid(sk), sk->dead, sk->sleep, sk->socket, sk->next, sk->prev, sk->err, sk->reuse, sk->zapped, sk->num, sk->protocol, sk->sndbuf, (unsigned int)sk->stamp.tv_sec, (unsigned int)sk->stamp.tv_usec, sk->socket->flags, sk->socket->type, sk->socket->state); } #endif /* CONFIG_IPSEC_DEBUG */ if (len >= max_content) { /* we've done all that can fit -- stop loop */ len = max_content; /* truncate crap */ break; } else { const off_t pos = begin + len; /* file position of end of what we've generated */ if (pos <= offset) { /* all is before first interesting character: * discard, but note where we are. */ len = 0; begin = pos; } } sk=sk->next; } *start = buffer + (offset - begin); /* Start of wanted data */ return len - (offset - begin); } #ifndef PROC_FS_2325 DEBUG_NO_STATIC #endif /* PROC_FS_2325 */ int pfkey_supported_get_info(char *buffer, char **start, off_t offset, int length #ifndef PROC_NO_DUMMY , int dummy #endif /* !PROC_NO_DUMMY */ ) { const int max_content = length > 0? length-1 : 0; off_t begin=0; int len=0; int satype; struct supported_list *pfkey_supported_p; len += ipsec_snprintf(buffer, length, "satype exttype alg_id ivlen minbits maxbits\n"); for(satype = SADB_SATYPE_UNSPEC; satype <= SADB_SATYPE_MAX; satype++) { pfkey_supported_p = pfkey_supported_list[satype]; while(pfkey_supported_p) { len += ipsec_snprintf(buffer+len, length-len, " %2d %2d %2d %3d %3d %3d\n", satype, pfkey_supported_p->supportedp->supported_alg_exttype, pfkey_supported_p->supportedp->supported_alg_id, pfkey_supported_p->supportedp->supported_alg_ivlen, pfkey_supported_p->supportedp->supported_alg_minbits, pfkey_supported_p->supportedp->supported_alg_maxbits); if (len >= max_content) { /* we've done all that can fit -- stop loop */ len = max_content; /* truncate crap */ break; } else { const off_t pos = begin + len; /* file position of end of what we've generated */ if (pos <= offset) { /* all is before first interesting character: * discard, but note where we are. */ len = 0; begin = pos; } } pfkey_supported_p = pfkey_supported_p->next; } } *start = buffer + (offset - begin); /* Start of wanted data */ return len - (offset - begin); } #ifndef PROC_FS_2325 DEBUG_NO_STATIC #endif /* PROC_FS_2325 */ int pfkey_registered_get_info(char *buffer, char **start, off_t offset, int length #ifndef PROC_NO_DUMMY , int dummy #endif /* !PROC_NO_DUMMY */ ) { const int max_content = length > 0? length-1 : 0; off_t begin=0; int len=0; int satype; struct socket_list *pfkey_sockets; len += ipsec_snprintf(buffer, length, "satype socket pid sk\n"); for(satype = SADB_SATYPE_UNSPEC; satype <= SADB_SATYPE_MAX; satype++) { pfkey_sockets = pfkey_registered_sockets[satype]; while(pfkey_sockets) { #ifdef NET_21 len += ipsec_snprintf(buffer+len, length-len, " %2d %8p %5d %8p\n", satype, pfkey_sockets->socketp, key_pid(pfkey_sockets->socketp->sk), pfkey_sockets->socketp->sk); #else /* NET_21 */ len += ipsec_snprintf(buffer+len, length-len, " %2d %8p N/A %8p\n", satype, pfkey_sockets->socketp, #if 0 key_pid((pfkey_sockets->socketp)->data), #endif (pfkey_sockets->socketp)->data); #endif /* NET_21 */ if (len >= max_content) { /* we've done all that can fit -- stop loop (could stop two) */ len = max_content; /* truncate crap */ break; } else { const off_t pos = begin + len; /* file position of end of what we've generated */ if (pos <= offset) { /* all is before first interesting character: * discard, but note where we are. */ len = 0; begin = pos; } } pfkey_sockets = pfkey_sockets->next; } } *start = buffer + (offset - begin); /* Start of wanted data */ return len - (offset - begin); } #ifndef PROC_FS_2325 struct proc_dir_entry proc_net_pfkey = { 0, 6, "pf_key", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, pfkey_get_info }; struct proc_dir_entry proc_net_pfkey_supported = { 0, 16, "pf_key_supported", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, pfkey_supported_get_info }; struct proc_dir_entry proc_net_pfkey_registered = { 0, 17, "pf_key_registered", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, pfkey_registered_get_info }; #endif /* !PROC_FS_2325 */ #endif /* CONFIG_PROC_FS */ DEBUG_NO_STATIC int supported_add_all(int satype, struct supported supported[], int size) { int i; int error = 0; KLIPS_PRINT(debug_pfkey, "klips_debug:init_pfkey: " "sizeof(supported_init_)[%d]/sizeof(struct supported)[%d]=%d.\n", satype, size, (int)sizeof(struct supported), (int)(size/sizeof(struct supported))); for(i = 0; i < size / sizeof(struct supported); i++) { KLIPS_PRINT(debug_pfkey, "klips_debug:init_pfkey: " "i=%d inserting satype=%d exttype=%d id=%d ivlen=%d minbits=%d maxbits=%d.\n", i, satype, supported[i].supported_alg_exttype, supported[i].supported_alg_id, supported[i].supported_alg_ivlen, supported[i].supported_alg_minbits, supported[i].supported_alg_maxbits); error |= pfkey_list_insert_supported(&(supported[i]), &(pfkey_supported_list[satype])); } return error; } DEBUG_NO_STATIC int supported_remove_all(int satype) { int error = 0; struct supported*supportedp; while(pfkey_supported_list[satype]) { supportedp = pfkey_supported_list[satype]->supportedp; KLIPS_PRINT(debug_pfkey, "klips_debug:init_pfkey: " "removing satype=%d exttype=%d id=%d ivlen=%d minbits=%d maxbits=%d.\n", satype, supportedp->supported_alg_exttype, supportedp->supported_alg_id, supportedp->supported_alg_ivlen, supportedp->supported_alg_minbits, supportedp->supported_alg_maxbits); error |= pfkey_list_remove_supported(supportedp, &(pfkey_supported_list[satype])); } return error; } int pfkey_init(void) { int error = 0; int i; static struct supported supported_init_ah[] = { #ifdef CONFIG_IPSEC_AUTH_HMAC_MD5 {SADB_EXT_SUPPORTED_AUTH, SADB_AALG_MD5_HMAC, 0, 128, 128}, #endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */ #ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1 {SADB_EXT_SUPPORTED_AUTH, SADB_AALG_SHA1_HMAC, 0, 160, 160} #endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */ }; static struct supported supported_init_esp[] = { #ifdef CONFIG_IPSEC_AUTH_HMAC_MD5 {SADB_EXT_SUPPORTED_AUTH, SADB_AALG_MD5_HMAC, 0, 128, 128}, #endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */ #ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1 {SADB_EXT_SUPPORTED_AUTH, SADB_AALG_SHA1_HMAC, 0, 160, 160}, #endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */ #ifdef CONFIG_IPSEC_ENC_3DES {SADB_EXT_SUPPORTED_ENCRYPT, SADB_EALG_3DES_CBC, 64, 168, 168}, #endif /* CONFIG_IPSEC_ENC_3DES */ }; static struct supported supported_init_ipip[] = { {SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_TALG_IPv4_in_IPv4, 0, 32, 32} #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) , {SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_TALG_IPv6_in_IPv4, 0, 128, 32} , {SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_TALG_IPv4_in_IPv6, 0, 32, 128} , {SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_TALG_IPv6_in_IPv6, 0, 128, 128} #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ }; #ifdef CONFIG_IPSEC_IPCOMP static struct supported supported_init_ipcomp[] = { {SADB_EXT_SUPPORTED_ENCRYPT, SADB_X_CALG_DEFLATE, 0, 1, 1} }; #endif /* CONFIG_IPSEC_IPCOMP */ #if 0 printk(KERN_INFO "klips_info:pfkey_init: " "FreeS/WAN: initialising PF_KEYv2 domain sockets.\n"); #endif for(i = SADB_SATYPE_UNSPEC; i <= SADB_SATYPE_MAX; i++) { pfkey_registered_sockets[i] = NULL; pfkey_supported_list[i] = NULL; } error |= supported_add_all(SADB_SATYPE_AH, supported_init_ah, sizeof(supported_init_ah)); error |= supported_add_all(SADB_SATYPE_ESP, supported_init_esp, sizeof(supported_init_esp)); #ifdef CONFIG_IPSEC_IPCOMP error |= supported_add_all(SADB_X_SATYPE_COMP, supported_init_ipcomp, sizeof(supported_init_ipcomp)); #endif /* CONFIG_IPSEC_IPCOMP */ error |= supported_add_all(SADB_X_SATYPE_IPIP, supported_init_ipip, sizeof(supported_init_ipip)); #ifdef NET_21 error |= sock_register(&pfkey_family_ops); #else /* NET_21 */ error |= sock_register(pfkey_proto_ops.family, &pfkey_proto_ops); #endif /* NET_21 */ #ifdef CONFIG_PROC_FS # ifndef PROC_FS_2325 # ifdef PROC_FS_21 error |= proc_register(proc_net, &proc_net_pfkey); error |= proc_register(proc_net, &proc_net_pfkey_supported); error |= proc_register(proc_net, &proc_net_pfkey_registered); # else /* PROC_FS_21 */ error |= proc_register_dynamic(&proc_net, &proc_net_pfkey); error |= proc_register_dynamic(&proc_net, &proc_net_pfkey_supported); error |= proc_register_dynamic(&proc_net, &proc_net_pfkey_registered); # endif /* PROC_FS_21 */ # else /* !PROC_FS_2325 */ proc_net_create ("pf_key", 0, pfkey_get_info); proc_net_create ("pf_key_supported", 0, pfkey_supported_get_info); proc_net_create ("pf_key_registered", 0, pfkey_registered_get_info); # endif /* !PROC_FS_2325 */ #endif /* CONFIG_PROC_FS */ return error; } int pfkey_cleanup(void) { int error = 0; printk(KERN_INFO "klips_info:pfkey_cleanup: " "shutting down PF_KEY domain sockets.\n"); #ifdef NET_21 error |= sock_unregister(PF_KEY); #else /* NET_21 */ error |= sock_unregister(pfkey_proto_ops.family); #endif /* NET_21 */ error |= supported_remove_all(SADB_SATYPE_AH); error |= supported_remove_all(SADB_SATYPE_ESP); #ifdef CONFIG_IPSEC_IPCOMP error |= supported_remove_all(SADB_X_SATYPE_COMP); #endif /* CONFIG_IPSEC_IPCOMP */ error |= supported_remove_all(SADB_X_SATYPE_IPIP); #ifdef CONFIG_PROC_FS # ifndef PROC_FS_2325 if (proc_net_unregister(proc_net_pfkey.low_ino) != 0) printk("klips_debug:pfkey_cleanup: " "cannot unregister /proc/net/pf_key\n"); if (proc_net_unregister(proc_net_pfkey_supported.low_ino) != 0) printk("klips_debug:pfkey_cleanup: " "cannot unregister /proc/net/pf_key_supported\n"); if (proc_net_unregister(proc_net_pfkey_registered.low_ino) != 0) printk("klips_debug:pfkey_cleanup: " "cannot unregister /proc/net/pf_key_registered\n"); # else /* !PROC_FS_2325 */ proc_net_remove ("pf_key"); proc_net_remove ("pf_key_supported"); proc_net_remove ("pf_key_registered"); # endif /* !PROC_FS_2325 */ #endif /* CONFIG_PROC_FS */ /* other module unloading cleanup happens here */ return error; } #ifdef MODULE #if 0 int init_module(void) { pfkey_init(); return 0; } void cleanup_module(void) { pfkey_cleanup(); } #endif /* 0 */ #else /* MODULE */ void pfkey_proto_init(struct net_proto *pro) { pfkey_init(); } #endif /* MODULE */ /* * $Log: pfkey_v2.c,v $ * Revision 1.4 2004/09/29 22:27:41 as * changed SADB identifiers * * Revision 1.3 2004/04/28 08:06:22 as * added dhr's freeswan-2.06 changes * * Revision 1.2 2004/03/22 21:53:19 as * merged alg-0.8.1 branch with HEAD * * Revision 1.1.4.1 2004/03/16 09:48:20 as * alg-0.8.1rc12 patch merged * * Revision 1.1 2004/03/15 20:35:26 as * added files from freeswan-2.04-x509-1.5.3 * * Revision 1.78 2003/04/03 17:38:09 rgb * Centralised ipsec_kfree_skb and ipsec_dev_{get,put}. * * Revision 1.77 2002/10/17 16:49:36 mcr * sock->ops should reference the unwrapped options so that * we get hacked in locking on SMP systems. * * Revision 1.76 2002/10/12 23:11:53 dhr * * [KenB + DHR] more 64-bit cleanup * * Revision 1.75 2002/09/20 05:01:57 rgb * Added memory allocation debugging. * * Revision 1.74 2002/09/19 02:42:50 mcr * do not define the pfkey_ops function for now. * * Revision 1.73 2002/09/17 17:29:23 mcr * #if 0 out some dead code - pfkey_ops is never used as written. * * Revision 1.72 2002/07/24 18:44:54 rgb * Type fiddling to tame ia64 compiler. * * Revision 1.71 2002/05/23 07:14:11 rgb * Cleaned up %p variants to 0p%p for test suite cleanup. * * Revision 1.70 2002/04/24 07:55:32 mcr * #include patches and Makefiles for post-reorg compilation. * * Revision 1.69 2002/04/24 07:36:33 mcr * Moved from ./klips/net/ipsec/pfkey_v2.c,v * * Revision 1.68 2002/03/08 01:15:17 mcr * put some internal structure only debug messages behind * && sysctl_ipsec_debug_verbose. * * Revision 1.67 2002/01/29 17:17:57 mcr * moved include of ipsec_param.h to after include of linux/kernel.h * otherwise, it seems that some option that is set in ipsec_param.h * screws up something subtle in the include path to kernel.h, and * it complains on the snprintf() prototype. * * Revision 1.66 2002/01/29 04:00:54 mcr * more excise of kversions.h header. * * Revision 1.65 2002/01/29 02:13:18 mcr * introduction of ipsec_kversion.h means that include of * ipsec_param.h must preceed any decisions about what files to * include to deal with differences in kernel source. * * Revision 1.64 2001/11/26 09:23:51 rgb * Merge MCR's ipsec_sa, eroute, proc and struct lifetime changes. * * Revision 1.61.2.1 2001/09/25 02:28:44 mcr * cleaned up includes. * * Revision 1.63 2001/11/12 19:38:00 rgb * Continue trying other sockets even if one fails and return only original * error. * * Revision 1.62 2001/10/18 04:45:22 rgb * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h, * lib/freeswan.h version macros moved to lib/kversions.h. * Other compiler directive cleanups. * * Revision 1.61 2001/09/20 15:32:59 rgb * Min/max cleanup. * * Revision 1.60 2001/06/14 19:35:12 rgb * Update copyright date. * * Revision 1.59 2001/06/13 15:35:48 rgb * Fixed #endif comments. * * Revision 1.58 2001/05/04 16:37:24 rgb * Remove erroneous checking of return codes for proc_net_* in 2.4. * * Revision 1.57 2001/05/03 19:43:36 rgb * Initialise error return variable. * Check error return codes in startup and shutdown. * Standardise on SENDERR() macro. * * Revision 1.56 2001/04/21 23:05:07 rgb * Define out skb->used for 2.4 kernels. * * Revision 1.55 2001/02/28 05:03:28 rgb * Clean up and rationalise startup messages. * * Revision 1.54 2001/02/27 22:24:55 rgb * Re-formatting debug output (line-splitting, joining, 1arg/line). * Check for satoa() return codes. * * Revision 1.53 2001/02/27 06:48:18 rgb * Fixed pfkey socket unregister log message to reflect type and function. * * Revision 1.52 2001/02/26 22:34:38 rgb * Fix error return code that was getting overwritten by the error return * code of an upmsg. * * Revision 1.51 2001/01/30 23:42:47 rgb * Allow pfkey msgs from pid other than user context required for ACQUIRE * and subsequent ADD or UDATE. * * Revision 1.50 2001/01/23 20:22:59 rgb * 2.4 fix to remove removed is_clone member. * * Revision 1.49 2000/11/06 04:33:47 rgb * Changed non-exported functions to DEBUG_NO_STATIC. * * Revision 1.48 2000/09/29 19:47:41 rgb * Update copyright. * * Revision 1.47 2000/09/22 04:23:04 rgb * Added more debugging to pfkey_upmsg() call from pfkey_sendmsg() error. * * Revision 1.46 2000/09/21 04:20:44 rgb * Fixed array size off-by-one error. (Thanks Svenning!) * * Revision 1.45 2000/09/20 04:01:26 rgb * Changed static functions to DEBUG_NO_STATIC for revealing function names * in oopsen. * * Revision 1.44 2000/09/19 00:33:17 rgb * 2.0 fixes. * * Revision 1.43 2000/09/16 01:28:13 rgb * Fixed use of 0 in p format warning. * * Revision 1.42 2000/09/16 01:09:41 rgb * Fixed debug format warning for pointers that was expecting ints. * * Revision 1.41 2000/09/13 15:54:00 rgb * Rewrote pfkey_get_info(), added pfkey_{supported,registered}_get_info(). * Moved supported algos add and remove to functions. * * Revision 1.40 2000/09/12 18:49:28 rgb * Added IPIP tunnel and IPCOMP register support. * * Revision 1.39 2000/09/12 03:23:49 rgb * Converted #if0 debugs to sysctl. * Removed debug_pfkey initialisations that prevented no_debug loading or * linking. * * Revision 1.38 2000/09/09 06:38:02 rgb * Return positive errno in pfkey_reply error message. * * Revision 1.37 2000/09/08 19:19:09 rgb * Change references from DEBUG_IPSEC to CONFIG_IPSEC_DEBUG. * Clean-up of long-unused crud... * Create pfkey error message on on failure. * Give pfkey_list_{insert,remove}_{socket,supported}() some error * checking. * * Revision 1.36 2000/09/01 18:49:38 rgb * Reap experimental NET_21_ bits. * Turned registered sockets list into an array of one list per satype. * Remove references to deprecated sklist_{insert,remove}_socket. * Removed leaking socket debugging code. * Removed duplicate pfkey_insert_socket in pfkey_create. * Removed all references to pfkey msg->msg_name, since it is not used for * pfkey. * Added a supported algorithms array lists, one per satype and registered * existing algorithms. * Fixed pfkey_list_{insert,remove}_{socket,support}() to allow change to * list. * Only send pfkey_expire() messages to sockets registered for that satype. * * Revision 1.35 2000/08/24 17:03:00 rgb * Corrected message size error return code for PF_KEYv2. * Removed downward error prohibition. * * Revision 1.34 2000/08/21 16:32:26 rgb * Re-formatted for cosmetic consistency and readability. * * Revision 1.33 2000/08/20 21:38:24 rgb * Added a pfkey_reply parameter to pfkey_msg_interp(). (Momchil) * Extended the upward message initiation of pfkey_sendmsg(). (Momchil) * * Revision 1.32 2000/07/28 14:58:31 rgb * Changed kfree_s to kfree, eliminating extra arg to fix 2.4.0-test5. * * Revision 1.31 2000/05/16 03:04:00 rgb * Updates for 2.3.99pre8 from MB. * * Revision 1.30 2000/05/10 19:22:21 rgb * Use sklist private functions for 2.3.xx compatibility. * * Revision 1.29 2000/03/22 16:17:03 rgb * Fixed SOCKOPS_WRAPPED macro for SMP (MB). * * Revision 1.28 2000/02/21 19:30:45 rgb * Removed references to pkt_bridged for 2.3.47 compatibility. * * Revision 1.27 2000/02/14 21:07:00 rgb * Fixed /proc/net/pf-key legend spacing. * * Revision 1.26 2000/01/22 03:46:59 rgb * Fixed pfkey error return mechanism so that we are able to free the * local copy of the pfkey_msg, plugging a memory leak and silencing * the bad object free complaints. * * Revision 1.25 2000/01/21 06:19:44 rgb * Moved pfkey_list_remove_socket() calls to before MOD_USE_DEC_COUNT. * Added debugging to pfkey_upmsg. * * Revision 1.24 2000/01/10 16:38:23 rgb * MB fixups for 2.3.x. * * Revision 1.23 1999/12/09 23:22:16 rgb * Added more instrumentation for debugging 2.0 socket * selection/reading. * Removed erroneous 2.0 wait==NULL check bug in select. * * Revision 1.22 1999/12/08 20:32:16 rgb * Tidied up 2.0.xx support, after major pfkey work, eliminating * msg->msg_name twiddling in the process, since it is not defined * for PF_KEYv2. * * Revision 1.21 1999/12/01 22:17:19 rgb * Set skb->dev to zero on new skb in case it is a reused skb. * Added check for skb_put overflow and freeing to avoid upmsg on error. * Added check for wrong pfkey version and freeing to avoid upmsg on * error. * Shut off content dumping in pfkey_destroy. * Added debugging message for size of buffer allocated for upmsg. * * Revision 1.20 1999/11/27 12:11:00 rgb * Minor clean-up, enabling quiet operation of pfkey if desired. * * Revision 1.19 1999/11/25 19:04:21 rgb * Update proc_fs code for pfkey to use dynamic registration. * * Revision 1.18 1999/11/25 09:07:17 rgb * Implemented SENDERR macro for propagating error codes. * Fixed error return code bug. * * Revision 1.17 1999/11/23 23:07:20 rgb * Change name of pfkey_msg_parser to pfkey_msg_interp since it no longer * parses. (PJO) * Sort out pfkey and freeswan headers, putting them in a library path. * * Revision 1.16 1999/11/20 22:00:22 rgb * Moved socketlist type declarations and prototypes for shared use. * Renamed reformatted and generically extended for use by other socket * lists pfkey_{del,add}_open_socket to pfkey_list_{remove,insert}_socket. * * Revision 1.15 1999/11/18 04:15:09 rgb * Make pfkey_data_ready temporarily available for 2.2.x testing. * Clean up pfkey_destroy_socket() debugging statements. * Add Peter Onion's code to send messages up to all listening sockets. * Changed all occurrences of #include "../../../lib/freeswan.h" * to #include which works due to -Ilibfreeswan in the * klips/net/ipsec/Makefile. * Replaced all kernel version macros to shorter, readable form. * Added CONFIG_PROC_FS compiler directives in case it is shut off. * * Revision 1.14 1999/11/17 16:01:00 rgb * Make pfkey_data_ready temporarily available for 2.2.x testing. * Clean up pfkey_destroy_socket() debugging statements. * Add Peter Onion's code to send messages up to all listening sockets. * Changed #include "../../../lib/freeswan.h" to #include * which works due to -Ilibfreeswan in the klips/net/ipsec/Makefile. * * Revision 1.13 1999/10/27 19:59:51 rgb * Removed af_unix comments that are no longer relevant. * Added debug prink statements. * Added to the /proc output in pfkey_get_info. * Made most functions non-static to enable oops tracing. * Re-enable skb dequeueing and freeing. * Fix skb_alloc() and skb_put() size bug in pfkey_upmsg(). * * Revision 1.12 1999/10/26 17:05:42 rgb * Complete re-ordering based on proto_ops structure order. * Separated out proto_ops structures for 2.0.x and 2.2.x for clarity. * Simplification to use built-in socket ops where possible for 2.2.x. * Add shorter macros for compiler directives to visually clean-up. * Add lots of sk skb dequeueing debugging statements. * Added to the /proc output in pfkey_get_info. * * Revision 1.11 1999/09/30 02:55:10 rgb * Bogus skb detection. * Fix incorrect /proc/net/ipsec-eroute printk message. * * Revision 1.10 1999/09/21 15:22:13 rgb * Temporary fix while I figure out the right way to destroy sockets. * * Revision 1.9 1999/07/08 19:19:44 rgb * Fix pointer format warning. * Fix missing member error under 2.0.xx kernels. * * Revision 1.8 1999/06/13 07:24:04 rgb * Add more debugging. * * Revision 1.7 1999/06/10 05:24:17 rgb * Clarified compiler directives. * Renamed variables to reduce confusion. * Used sklist_*_socket() kernel functions to simplify 2.2.x socket support. * Added lots of sanity checking. * * Revision 1.6 1999/06/03 18:59:50 rgb * More updates to 2.2.x socket support. Almost works, oops at end of call. * * Revision 1.5 1999/05/25 22:44:05 rgb * Start fixing 2.2 sockets. * * Revision 1.4 1999/04/29 15:21:34 rgb * Move log to the end of the file. * Eliminate min/max redefinition in #include . * Correct path for pfkey #includes * Standardise an error return method. * Add debugging instrumentation. * Move message type checking to pfkey_msg_parse(). * Add check for errno incorrectly set. * Add check for valid PID. * Add check for reserved illegally set. * Add check for message out of bounds. * * Revision 1.3 1999/04/15 17:58:07 rgb * Add RCSID labels. * * Revision 1.2 1999/04/15 15:37:26 rgb * Forward check changes from POST1_00 branch. * * Revision 1.1.2.2 1999/04/13 20:37:12 rgb * Header Title correction. * * Revision 1.1.2.1 1999/03/26 20:58:55 rgb * Add pfkeyv2 support to KLIPS. * * * RFC 2367 * PF_KEY_v2 Key Management API */