📄 af_ipx.c
字号:
#ifdef CONFIG_IPX_INTERN if(sk->protinfo.af_ipx.intrfc) memcpy(uaddr.sipx_node, sk->protinfo.af_ipx.intrfc->if_node,IPX_NODE_LEN); else return -ENETDOWN; /* Someone zonked the iface */#endif /* CONFIG_IPX_INTERN */ ret = ipx_bind(sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx)); if(ret != 0) return (ret); } /* We can either connect to primary network or somewhere we can route to */ if( !(addr->sipx_network == 0 && ipx_primary_net != NULL) && ipxrtr_lookup(addr->sipx_network) == NULL) return (-ENETUNREACH); sk->protinfo.af_ipx.dest_addr.net = addr->sipx_network; sk->protinfo.af_ipx.dest_addr.sock = addr->sipx_port; memcpy(sk->protinfo.af_ipx.dest_addr.node, addr->sipx_node,IPX_NODE_LEN); sk->protinfo.af_ipx.type = addr->sipx_type; if(sock->type == SOCK_DGRAM ) { sock->state = SS_CONNECTED; sk->state = TCP_ESTABLISHED; } return (0);}static int ipx_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer){ ipx_address *addr; struct sockaddr_ipx sipx; struct sock *sk; sk = sock->sk; *uaddr_len = sizeof(struct sockaddr_ipx); if(peer) { if(sk->state != TCP_ESTABLISHED) return (-ENOTCONN); addr = &sk->protinfo.af_ipx.dest_addr; sipx.sipx_network = addr->net; memcpy(sipx.sipx_node,addr->node,IPX_NODE_LEN); sipx.sipx_port = addr->sock; } else { if(sk->protinfo.af_ipx.intrfc != NULL) { sipx.sipx_network=sk->protinfo.af_ipx.intrfc->if_netnum;#ifdef CONFIG_IPX_INTERN memcpy(sipx.sipx_node, sk->protinfo.af_ipx.node, IPX_NODE_LEN);#else memcpy(sipx.sipx_node, sk->protinfo.af_ipx.intrfc->if_node, IPX_NODE_LEN);#endif /* CONFIG_IPX_INTERN */ } else { sipx.sipx_network = 0; memset(sipx.sipx_node, '\0', IPX_NODE_LEN); } sipx.sipx_port = sk->protinfo.af_ipx.port; } sipx.sipx_family = AF_IPX; sipx.sipx_type = sk->protinfo.af_ipx.type; memcpy(uaddr,&sipx,sizeof(sipx)); return (0);}int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt){ /* NULL here for pt means the packet was looped back */ ipx_interface *intrfc; struct ipxhdr *ipx; int ret; ipx = skb->nh.ipxh; /* Too small? */ if(ntohs(ipx->ipx_pktsize) < sizeof(struct ipxhdr)) goto drop; /* Invalid header */ if(ntohs(ipx->ipx_pktsize) > skb->len) goto drop; /* Not ours */ if (skb->pkt_type == PACKET_OTHERHOST) goto drop; if(ipx->ipx_checksum != IPX_NO_CHECKSUM) { if(ipx_set_checksum(ipx, ntohs(ipx->ipx_pktsize)) != ipx->ipx_checksum) goto drop; } /* Determine what local ipx endpoint this is */ intrfc = ipxitf_find_using_phys(dev, pt->type); if(intrfc == NULL) { if(ipxcfg_auto_create_interfaces && ntohl(ipx->ipx_dest.net) != 0L) { intrfc = ipxitf_auto_create(dev, pt->type); ipxitf_hold(intrfc); } if(intrfc == NULL) /* Not one of ours */ goto drop; } ret = ipxitf_rcv(intrfc, skb); ipxitf_put(intrfc); return ret;drop: kfree_skb(skb); return (0);}static int ipx_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm){ struct sock *sk = sock->sk; struct sockaddr_ipx *usipx=(struct sockaddr_ipx *)msg->msg_name; struct sockaddr_ipx local_sipx; int retval; int flags = msg->msg_flags; /* Socket gets bound below anyway *//* if(sk->zapped) return (-EIO); */ /* Socket not bound */ if(flags & ~MSG_DONTWAIT) return (-EINVAL); if(usipx) { if(sk->protinfo.af_ipx.port == 0) { struct sockaddr_ipx uaddr; int ret; uaddr.sipx_port = 0; uaddr.sipx_network = 0L;#ifdef CONFIG_IPX_INTERN if(sk->protinfo.af_ipx.intrfc) memcpy(uaddr.sipx_node, sk->protinfo.af_ipx.intrfc ->if_node,IPX_NODE_LEN); else return -ENETDOWN; /* Someone zonked the iface */#endif ret = ipx_bind(sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx)); if(ret != 0) return (ret); } if(msg->msg_namelen < sizeof(*usipx)) return (-EINVAL); if(usipx->sipx_family != AF_IPX) return (-EINVAL); } else { if(sk->state != TCP_ESTABLISHED) return (-ENOTCONN); usipx=&local_sipx; usipx->sipx_family = AF_IPX; usipx->sipx_type = sk->protinfo.af_ipx.type; usipx->sipx_port = sk->protinfo.af_ipx.dest_addr.sock; usipx->sipx_network = sk->protinfo.af_ipx.dest_addr.net; memcpy(usipx->sipx_node,sk->protinfo.af_ipx.dest_addr.node,IPX_NODE_LEN); } retval = ipxrtr_route_packet(sk, usipx, msg->msg_iov, len, flags&MSG_DONTWAIT); if(retval < 0) return (retval); return (len);}static int ipx_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm){ struct sock *sk = sock->sk; struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)msg->msg_name; struct ipxhdr *ipx = NULL; struct sk_buff *skb; int copied, err; /* put the autobinding in */ if(sk->protinfo.af_ipx.port == 0) { struct sockaddr_ipx uaddr; int ret; uaddr.sipx_port = 0; uaddr.sipx_network = 0;#ifdef CONFIG_IPX_INTERN if(sk->protinfo.af_ipx.intrfc) memcpy(uaddr.sipx_node, sk->protinfo.af_ipx.intrfc->if_node,IPX_NODE_LEN); else return -ENETDOWN; /* Someone zonked the iface */#endif /* CONFIG_IPX_INTERN */ ret = ipx_bind(sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx)); if(ret != 0) return (ret); } if(sk->zapped) return (-ENOTCONN); skb = skb_recv_datagram(sk,flags&~MSG_DONTWAIT,flags&MSG_DONTWAIT,&err); if(!skb) goto out; ipx = skb->nh.ipxh; copied = ntohs(ipx->ipx_pktsize) - sizeof(struct ipxhdr); if(copied > size) { copied=size; msg->msg_flags |= MSG_TRUNC; } err = skb_copy_datagram_iovec(skb, sizeof(struct ipxhdr), msg->msg_iov, copied); if(err) goto out_free; sk->stamp = skb->stamp; msg->msg_namelen = sizeof(*sipx); if(sipx) { sipx->sipx_family = AF_IPX; sipx->sipx_port = ipx->ipx_source.sock; memcpy(sipx->sipx_node,ipx->ipx_source.node,IPX_NODE_LEN); sipx->sipx_network = ipx->ipx_source.net; sipx->sipx_type = ipx->ipx_type; } err = copied;out_free: skb_free_datagram(sk, skb);out: return (err);}static int ipx_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg){ long amount = 0; struct sock *sk = sock->sk; switch(cmd) { case TIOCOUTQ: amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); if(amount < 0) amount = 0; return (put_user(amount, (int *)arg)); case TIOCINQ: { struct sk_buff *skb; /* These two are safe on a single CPU system as only user tasks fiddle here */ if((skb = skb_peek(&sk->receive_queue)) != NULL) amount = skb->len - sizeof(struct ipxhdr); return (put_user(amount, (int *)arg)); } case SIOCADDRT: case SIOCDELRT: if(!capable(CAP_NET_ADMIN)) return (-EPERM); return (ipxrtr_ioctl(cmd,(void *)arg)); case SIOCSIFADDR: case SIOCAIPXITFCRT: case SIOCAIPXPRISLT: if(!capable(CAP_NET_ADMIN)) return (-EPERM); case SIOCGIFADDR: return (ipxitf_ioctl(cmd,(void *)arg)); case SIOCIPXCFGDATA: return (ipxcfg_get_config_data((void *)arg)); case SIOCIPXNCPCONN: { /* * This socket wants to take care of the NCP connection * handed to us in arg. */ if (!capable(CAP_NET_ADMIN)) return(-EPERM); return get_user(sk->protinfo.af_ipx.ipx_ncp_conn, (const unsigned short *)(arg)); } case SIOCGSTAMP: { int ret = -EINVAL; if(sk) { if(sk->stamp.tv_sec == 0) return (-ENOENT); ret = -EFAULT; if(!copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval))) ret = 0; } return (ret); } case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: case SIOCGIFBRDADDR: case SIOCSIFBRDADDR: case SIOCGIFNETMASK: case SIOCSIFNETMASK: return (-EINVAL); default: return (dev_ioctl(cmd,(void *) arg)); } /*NOT REACHED*/ return (0);}/* * SPX interface support */int ipx_register_spx(struct proto_ops **p, struct net_proto_family *spx){ if(spx_family_ops!=NULL) return -EBUSY; cli(); MOD_INC_USE_COUNT; *p=&ipx_dgram_ops; spx_family_ops=spx; sti(); return 0;}int ipx_unregister_spx(void){ spx_family_ops=NULL; MOD_DEC_USE_COUNT; return 0;}/* * Socket family declarations */static struct net_proto_family ipx_family_ops = { PF_IPX, ipx_create};static struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = { family: PF_IPX, release: ipx_release, bind: ipx_bind, connect: ipx_connect, socketpair: sock_no_socketpair, accept: sock_no_accept, getname: ipx_getname, poll: datagram_poll, ioctl: ipx_ioctl, listen: sock_no_listen, shutdown: sock_no_shutdown, /* FIXME: We have to really support shutdown. */ setsockopt: ipx_setsockopt, getsockopt: ipx_getsockopt, sendmsg: ipx_sendmsg, recvmsg: ipx_recvmsg, mmap: sock_no_mmap,};#include <linux/smp_lock.h>SOCKOPS_WRAP(ipx_dgram, PF_IPX);static struct packet_type ipx_8023_packet_type ={ __constant_htons(ETH_P_802_3), NULL, /* All devices */ ipx_rcv, NULL, NULL,};static struct packet_type ipx_dix_packet_type ={ __constant_htons(ETH_P_IPX), NULL, /* All devices */ ipx_rcv, NULL, NULL,};static struct notifier_block ipx_dev_notifier={ ipxitf_device_event, NULL, 0};extern struct datalink_proto *make_EII_client(void);extern struct datalink_proto *make_8023_client(void);extern void destroy_EII_client(struct datalink_proto *);extern void destroy_8023_client(struct datalink_proto *);static unsigned char ipx_8022_type = 0xE0;static unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 };static int __init ipx_init(void){ (void) sock_register(&ipx_family_ops); pEII_datalink = make_EII_client(); dev_add_pack(&ipx_dix_packet_type); p8023_datalink = make_8023_client(); dev_add_pack(&ipx_8023_packet_type); if((p8022_datalink = register_8022_client(ipx_8022_type,ipx_rcv)) == NULL) printk(KERN_CRIT "IPX: Unable to register with 802.2\n"); if((pSNAP_datalink = register_snap_client(ipx_snap_id,ipx_rcv)) == NULL) printk(KERN_CRIT "IPX: Unable to register with SNAP\n"); register_netdevice_notifier(&ipx_dev_notifier);#ifdef CONFIG_PROC_FS proc_net_create("ipx", 0, ipx_get_info); proc_net_create("ipx_interface", 0, ipx_interface_get_info); proc_net_create("ipx_route", 0, ipx_rt_get_info);#endif printk(KERN_INFO "NET4: Linux IPX 0.42v4 for NET4.0\n"); printk(KERN_INFO "IPX Portions Copyright (c) 1995 Caldera, Inc.\n"); printk(KERN_INFO "IPX Portions Copyright (c) 2000 Conectiva, Inc.\n"); return 0;}module_init(ipx_init);/* Higher layers need this info to prep tx pkts */int ipx_if_offset(unsigned long ipx_net_number){ ipx_route *rt = NULL; rt = ipxrtr_lookup(ipx_net_number); return (rt ? rt->ir_intrfc->if_ipx_offset : -ENETUNREACH);}/* Export symbols for higher layers */EXPORT_SYMBOL(ipxrtr_route_skb);EXPORT_SYMBOL(ipx_if_offset);EXPORT_SYMBOL(ipx_remove_socket);EXPORT_SYMBOL(ipx_register_spx);EXPORT_SYMBOL(ipx_unregister_spx);/* Note on MOD_{INC,DEC}_USE_COUNT: * * Use counts are incremented/decremented when * sockets are created/deleted. * * Routes are always associated with an interface, and * allocs/frees will remain properly accounted for by * their associated interfaces. * * Ergo, before the ipx module can be removed, all IPX * sockets be closed from user space. */#ifdef MODULEstatic void ipx_proto_finito(void){ /* no need to worry about having anything on the ipx_interfaces * list, when a interface is created we increment the module * usage count, so the module will only be unloaded when there * are no more interfaces */ proc_net_remove("ipx_route"); proc_net_remove("ipx_interface"); proc_net_remove("ipx"); unregister_netdevice_notifier(&ipx_dev_notifier); unregister_snap_client(ipx_snap_id); pSNAP_datalink = NULL; unregister_8022_client(ipx_8022_type); p8022_datalink = NULL; dev_remove_pack(&ipx_8023_packet_type); destroy_8023_client(p8023_datalink); p8023_datalink = NULL; dev_remove_pack(&ipx_dix_packet_type); destroy_EII_client(pEII_datalink); pEII_datalink = NULL; (void) sock_unregister(ipx_family_ops.family); return;}module_exit(ipx_proto_finito);#endif /* MODULE */#endif /* CONFIG_IPX || CONFIG_IPX_MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -