static int rtmac_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct rtmac_config cfg; struct rtnet_device *rtdev; if( !suser() ) return -EPERM; if( copy_from_user(&cfg, (void*)arg, sizeof(struct rtmac_config)) ) return -EFAULT; rtdev = rtdev_get_by_name(cfg.if_name); if( !rtdev ) { rt_printk("RTmac: invalid interface %s\n", cfg.if_name); return -ENODEV; } if( !(rtdev->rtmac && rtdev->rtmac->ioctl_ops) ) { return -ENOTTY; } switch( cmd ) { case RTMAC_IOC_CLIENT: return rtmac_ioctl_client(rtdev); break; case RTMAC_IOC_MASTER: return rtmac_ioctl_master(rtdev, cfg.cycle, cfg.mtu); break; case RTMAC_IOC_UP: return rtmac_ioctl_up(rtdev); break; case RTMAC_IOC_DOWN: return rtmac_ioctl_down(rtdev); break; case RTMAC_IOC_ADD: return rtmac_ioctl_add(rtdev, cfg.ip_addr); break; case RTMAC_IOC_REMOVE: return rtmac_ioctl_remove(rtdev, cfg.ip_addr); break; case RTMAC_IOC_ADD_NRT: return rtmac_ioctl_add_nrt(rtdev, cfg.ip_addr); break; case RTMAC_IOC_REMOVE_NRT: return rtmac_ioctl_remove_nrt(rtdev, cfg.ip_addr); break; case RTMAC_IOC_CYCLE: return rtmac_ioctl_cycle(rtdev, cfg.cycle); break; case RTMAC_IOC_MTU: return rtmac_ioctl_mtu(rtdev, cfg.mtu); break; case RTMAC_IOC_OFFSET: return rtmac_ioctl_offset(rtdev, cfg.ip_addr, cfg.offset); default: return -ENOTTY; } }
void rtmac_release(void) { rt_printk("RTmac: end realtime medium access control\n"); tdma_stop(rtdev_get_by_name(dev)); #ifdef CONFIG_PROC_FS rtmac_proc_release(); #endif rtmac_chrdev_release(); }
/*** * rtdev_alloc_name - allocate a name for the rtnet_device * @rtdev: the rtnet_device * @name_mask: a name mask (e.g. "rteth%d" for ethernet) * * This function have to be called from the driver probe function. */ void rtdev_alloc_name(struct rtnet_device *rtdev, const char *mask) { char buf[IFNAMSIZ]; int i; struct rtnet_device *tmp; for (i = 0; i < MAX_RT_DEVICES; i++) { snprintf(buf, IFNAMSIZ, mask, i); if ((tmp = rtdev_get_by_name(buf)) == NULL) { strncpy(rtdev->name, buf, IFNAMSIZ); break; } else rtdev_dereference(tmp); } }
int rtmac_init(void) { int ret = 0; rt_printk("RTmac: init realtime medium access control\n"); ret = tdma_start(rtdev_get_by_name(dev)); if (ret) return ret; #ifdef CONFIG_PROC_FS ret = rtmac_proc_register(); if (ret) return ret; #endif ret = rtmac_chrdev_init(); if (ret) return ret; return ret; }
/*** * rt_socket_if_ioctl */ int rt_socket_if_ioctl(struct rtdm_dev_context *context, int call_flags, int request, void *arg) { struct rtnet_device *rtdev; struct ifreq *cur_ifr; struct sockaddr_in *sin; int i; int size; struct ifconf *ifc = arg; struct ifreq *ifr = arg; int ret = 0; switch (request) { case SIOCGIFCONF: size = 0; cur_ifr = ifc->ifc_req; for (i = 1; i <= MAX_RT_DEVICES; i++) { rtdev = rtdev_get_by_index(i); if (rtdev != NULL) { if ((rtdev->flags & IFF_RUNNING) == 0) { rtdev_dereference(rtdev); continue; } size += sizeof(struct ifreq); if (size > ifc->ifc_len) { rtdev_dereference(rtdev); size = ifc->ifc_len; break; } strncpy(cur_ifr->ifr_name, rtdev->name, IFNAMSIZ); sin = (struct sockaddr_in *)&cur_ifr->ifr_addr; sin->sin_family = AF_INET; sin->sin_addr.s_addr = rtdev->local_ip; cur_ifr++; rtdev_dereference(rtdev); } } ifc->ifc_len = size; break; case SIOCGIFFLAGS: rtdev = rtdev_get_by_name(ifr->ifr_name); if (rtdev == NULL) return -ENODEV; else { ifr->ifr_flags = rtdev->flags; rtdev_dereference(rtdev); } break; default: ret = -EOPNOTSUPP; break; } return ret; }
int rtwlan_tx(struct rtskb *rtskb, struct rtnet_device *rtnet_dev) { struct rtwlan_device * rtwlan = rtnetdev_priv(rtnet_dev); struct ieee80211_hdr_3addr header = { /* Ensure zero initialized */ .duration_id = 0, .seq_ctl = 0 }; u8 dest[ETH_ALEN], src[ETH_ALEN]; /* Save source and destination addresses */ memcpy(dest, rtskb->data, ETH_ALEN); memcpy(src, rtskb->data + ETH_ALEN, ETH_ALEN); /* Generate ieee80211 compatible header */ memcpy(header.addr3, src, ETH_ALEN); /* BSSID */ memcpy(header.addr2, src, ETH_ALEN); /* SA */ memcpy(header.addr1, dest, ETH_ALEN); /* DA */ /* Frame Control */ switch(rtwlan->mode) { case RTWLAN_MODE_RAW: header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); break; case RTWLAN_MODE_ACK: header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); break; default: return -1; } memcpy(rtskb_push(rtskb, IEEE80211_3ADDR_LEN), &header, IEEE80211_3ADDR_LEN); return 0; } EXPORT_SYMBOL(rtwlan_tx); /** * rtalloc_wlandev - Allocates and sets up a wlan device * @sizeof_priv: size of additional driver-private structure to * be allocated for this wlan device * * Fill in the fields of the device structure with wlan-generic * values. Basically does everything except registering the device. * * A 32-byte alignment is enforced for the private data area. */ struct rtnet_device * rtwlan_alloc_dev(int sizeof_priv) { struct rtnet_device *rtnet_dev; RTWLAN_DEBUG("Start.\n"); rtnet_dev = rt_alloc_etherdev(sizeof(struct rtwlan_device) + sizeof_priv); if (!rtnet_dev) return NULL; rtdev_alloc_name(rtnet_dev, "rtwlan%d"); return rtnet_dev; } EXPORT_SYMBOL(rtwlan_alloc_dev); int rtwlan_ioctl(struct rtnet_device * rtdev, unsigned int request, unsigned long arg) { struct rtwlan_cmd cmd; int ret=0; if (copy_from_user(&cmd, (void *)arg, sizeof(cmd)) != 0) return -EFAULT; switch(request) { case IOC_RTWLAN_IFINFO: if (cmd.args.info.ifindex > 0) rtdev = rtdev_get_by_index(cmd.args.info.ifindex); else rtdev = rtdev_get_by_name(cmd.head.if_name); if (rtdev == NULL) return -ENODEV; if (down_interruptible(&rtdev->nrt_lock)) { rtdev_dereference(rtdev); return -ERESTARTSYS; } if (rtdev->do_ioctl) ret = rtdev->do_ioctl(rtdev, request, &cmd); else ret = -ENORTWLANDEV; memcpy(cmd.head.if_name, rtdev->name, IFNAMSIZ); cmd.args.info.ifindex = rtdev->ifindex; cmd.args.info.flags = rtdev->flags; up(&rtdev->nrt_lock); rtdev_dereference(rtdev); break; case IOC_RTWLAN_MODE: case IOC_RTWLAN_BITRATE: case IOC_RTWLAN_CHANNEL: case IOC_RTWLAN_TXPOWER: case IOC_RTWLAN_DROPBCAST: case IOC_RTWLAN_DROPMCAST: case IOC_RTWLAN_REGREAD: case IOC_RTWLAN_REGWRITE: case IOC_RTWLAN_BBPWRITE: case IOC_RTWLAN_BBPREAD: case IOC_RTWLAN_BBPSENS: if (down_interruptible(&rtdev->nrt_lock)) return -ERESTARTSYS; if (rtdev->do_ioctl) ret = rtdev->do_ioctl(rtdev, request, &cmd); else ret = -ENORTWLANDEV; up(&rtdev->nrt_lock); break; default: ret = -ENOTTY; } if (copy_to_user((void *)arg, &cmd, sizeof(cmd)) != 0) return -EFAULT; return ret; } struct rtnet_ioctls rtnet_wlan_ioctls = { service_name: "rtwlan ioctl", ioctl_type: RTNET_IOC_TYPE_RTWLAN, handler: rtwlan_ioctl };
/*** * rt_socket_if_ioctl */ int rt_socket_if_ioctl(struct rtdm_dev_context *sockctx, rtdm_user_info_t *user_info, int request, void *arg) { struct rtnet_device *rtdev; struct ifreq *ifr = arg; struct sockaddr_in *sin; int ret = 0; if (request == SIOCGIFCONF) { struct ifconf *ifc = arg; struct ifreq *cur_ifr = ifc->ifc_req; int size = 0; int i; for (i = 1; i <= MAX_RT_DEVICES; i++) { rtdev = rtdev_get_by_index(i); if (rtdev != NULL) { if ((rtdev->flags & IFF_RUNNING) == 0) { rtdev_dereference(rtdev); continue; } size += sizeof(struct ifreq); if (size > ifc->ifc_len) { rtdev_dereference(rtdev); size = ifc->ifc_len; break; } strncpy(cur_ifr->ifr_name, rtdev->name, IFNAMSIZ); sin = (struct sockaddr_in *)&cur_ifr->ifr_addr; sin->sin_family = AF_INET; sin->sin_addr.s_addr = rtdev->local_ip; cur_ifr++; rtdev_dereference(rtdev); } } ifc->ifc_len = size; return 0; } rtdev = rtdev_get_by_name(ifr->ifr_name); if (rtdev == NULL) return -ENODEV; switch (request) { case SIOCGIFINDEX: ifr->ifr_ifindex = rtdev->ifindex; break; case SIOCGIFFLAGS: ifr->ifr_flags = rtdev->flags; break; case SIOCGIFHWADDR: memcpy(ifr->ifr_hwaddr.sa_data, rtdev->dev_addr, rtdev->addr_len); ifr->ifr_hwaddr.sa_family = rtdev->type; break; case SIOCGIFADDR: sin = (struct sockaddr_in *)&ifr->ifr_addr; sin->sin_family = AF_INET; sin->sin_addr.s_addr = rtdev->local_ip; break; case SIOCETHTOOL: if (rtdev->do_ioctl != NULL) ret = rtdev->do_ioctl(rtdev, request, arg); else ret = -EOPNOTSUPP; break; default: ret = -EOPNOTSUPP; break; } rtdev_dereference(rtdev); return ret; }
/** * rtnet_ioctl - * @inode: * @file: * @cmd: * @arg: */ static int rtnet_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct rtnet_config cfg; struct rtnet_device *rtdev; int ret; if (!suser())return -EPERM; ret = copy_from_user(&cfg, (void *)arg, sizeof(cfg)); if (ret) return -EFAULT; rtdev = rtdev_get_by_name(cfg.if_name); if ( !rtdev ) { rt_printk("RTnet: invalid interface %s\n", cfg.if_name); return -ENODEV; } switch(cmd){ case IOC_RT_IFUP: ret = rtdev_open(rtdev); // = 0, if dev already up /* * if device already up and ip changes, delete routing table and add new route * if the dev changes state from close->open also add new route * * pretty ugly, isn't it ;) * */ if( ret == 0 ) { if( rtdev->local_addr != cfg.ip_addr ) { rt_ip_route_del(rtdev); rtdev->local_addr = cfg.ip_addr; rt_ip_route_add(rtdev, cfg.ip_netaddr, cfg.ip_mask); rt_arp_table_add(cfg.ip_addr, rtdev->dev_addr); rt_ip_route_add_specific(rtdev, cfg.ip_broadcast, rtdev->broadcast); } } else { rtdev->local_addr = cfg.ip_addr; rt_ip_route_add(rtdev, cfg.ip_netaddr, cfg.ip_mask); rt_arp_table_add(cfg.ip_addr, rtdev->dev_addr); rt_ip_route_add_specific(rtdev, cfg.ip_broadcast, rtdev->broadcast); } return 0; case IOC_RT_IFDOWN: /* * if rtmac is active on dev, don't shut it down.... * * FIXME: if mac exists shut mac down, then device... */ if( rtdev->rtmac ) { rt_printk("rtnet: rtmac is active on dev %s, cannot shut down\n", rtdev->name); return -ENOTTY; } rt_ip_route_del(rtdev); rtdev_close(rtdev); return 0; case IOC_RT_ROUTE_SOLICIT: rt_arp_solicit(rtdev,cfg.ip_addr); return 0; case IOC_RT_ROUTE_DELETE: // Billa: delete an ARP & ROUTE element in the lists rt_arp_table_del(cfg.ip_addr); rt_ip_route_del_specific(rtdev,cfg.ip_addr); return 0; default: return -ENOTTY; } }