📄 comx-proto-fr.c
字号:
newskb->dev=fr->master; dev_queue_xmit(newskb); ch->stats.tx_bytes += skb->len; ch->stats.tx_packets++; dev_kfree_skb(skb); } else { netif_stop_queue(dev); for (; dir ; dir = dir->next) { if(!S_ISDIR(dir->mode)) { continue; } if ((sdev = dir->data) && (sch = sdev->priv) && (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) && (sfr->master == dev) && (netif_queue_stopped(sdev))) { netif_stop_queue(sdev); } } switch(mch->HW_send_packet(dev, skb)) { case FRAME_QUEUED: netif_wake_queue(dev); break; case FRAME_ACCEPTED: case FRAME_DROPPED: break; case FRAME_ERROR: printk(KERN_ERR "%s: Transmit frame error (len %d)\n", dev->name, skb->len); break; } } return 0;}static int fr_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len) { struct comx_channel *ch = dev->priv; struct fr_data *fr = ch->LINE_privdata; skb_push(skb, dev->hard_header_len); /* Put in DLCI */ skb->data[0] = (fr->dlci & (1024 - 15)) >> 2; skb->data[1] = (fr->dlci & 15) << 4 | 1; // EA bit 1 skb->data[2] = FRAD_UI; skb->data[3] = NLPID_IP; return dev->hard_header_len; }static int fr_statistics(struct net_device *dev, char *page) { struct comx_channel *ch = dev->priv; struct fr_data *fr = ch->LINE_privdata; int len = 0; if (fr->master == dev) { struct proc_dir_entry *dir = ch->procdir->parent->subdir; struct net_device *sdev; struct comx_channel *sch; struct fr_data *sfr; int slaves = 0; len += sprintf(page + len, "This is a Frame Relay master device\nSlaves: "); for (; dir ; dir = dir->next) { if(!S_ISDIR(dir->mode)) { continue; } if ((sdev = dir->data) && (sch = sdev->priv) && (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) && (sfr->master == dev) && (sdev != dev)) { slaves++; len += sprintf(page + len, "%s ", sdev->name); } } len += sprintf(page + len, "%s\n", slaves ? "" : "(none)"); if (fr->keepa_freq) { len += sprintf(page + len, "Line keepalive (value %d) " "status %s [%d]\n", fr->keepa_freq, ch->line_status & PROTO_LOOP ? "LOOP" : ch->line_status & PROTO_UP ? "UP" : "DOWN", fr->keepalivecnt); } else { len += sprintf(page + len, "Line keepalive protocol " "is not set\n"); } } else { // if slave len += sprintf(page + len, "This is a Frame Relay slave device, master: %s\n", fr->master ? fr->master->name : "(not set)"); } return len;}static int fr_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ struct proc_dir_entry *file = (struct proc_dir_entry *)data; struct net_device *dev = file->parent->data; struct comx_channel *ch = dev->priv; struct fr_data *fr = NULL; int len = 0; if (ch) { fr = ch->LINE_privdata; } if (strcmp(file->name, FILENAME_DLCI) == 0) { len = sprintf(page, "%04d\n", fr->dlci); } else if (strcmp(file->name, FILENAME_MASTER) == 0) { len = sprintf(page, "%-9s\n", fr->master ? fr->master->name : "(none)"); } else if (strcmp(file->name, FILENAME_KEEPALIVE) == 0) { len = fr->keepa_freq ? sprintf(page, "% 3d\n", fr->keepa_freq) : sprintf(page, "off\n"); } else { printk(KERN_ERR "comxfr: internal error, filename %s\n", file->name); return -EBADF; } if (off >= len) { *eof = 1; return 0; } *start = page + off; if (count >= len - off) *eof = 1; return min_t(int, count, len - off);}static int fr_write_proc(struct file *file, const char *buffer, u_long count, void *data){ struct proc_dir_entry *entry = (struct proc_dir_entry *)data; struct net_device *dev = entry->parent->data; struct comx_channel *ch = dev->priv; struct fr_data *fr = NULL; char *page; if (ch) { fr = ch->LINE_privdata; } if (!(page = (char *)__get_free_page(GFP_KERNEL))) { return -ENOMEM; } copy_from_user(page, buffer, count); if (*(page + count - 1) == '\n') { *(page + count - 1) = 0; } if (strcmp(entry->name, FILENAME_DLCI) == 0) { u16 dlci_new = simple_strtoul(page, NULL, 10); if (dlci_new > 1023) { printk(KERN_ERR "Invalid DLCI value\n"); } else fr->dlci = dlci_new; } else if (strcmp(entry->name, FILENAME_MASTER) == 0) { struct net_device *new_master = dev_get_by_name(page); if (new_master && new_master->type == ARPHRD_FRAD) { struct comx_channel *sch = new_master->priv; struct fr_data *sfr = sch->LINE_privdata; if (sfr && sfr->master == new_master) { if(fr->master) dev_put(fr->master); fr->master = new_master; /* Megorokli a master statuszat */ ch->line_status = sch->line_status; } } } else if (strcmp(entry->name, FILENAME_KEEPALIVE) == 0) { int keepa_new = -1; if (strcmp(page, KEEPALIVE_OFF) == 0) { keepa_new = 0; } else { keepa_new = simple_strtoul(page, NULL, 10); } if (keepa_new < 0 || keepa_new > 100) { printk(KERN_ERR "invalid keepalive\n"); } else { if (fr->keepa_freq && keepa_new != fr->keepa_freq) { fr_set_keepalive(dev, 0); } if (keepa_new) { fr_set_keepalive(dev, keepa_new); } } } else { printk(KERN_ERR "comxfr_write_proc: internal error, filename %s\n", entry->name); count = -EBADF; } free_page((unsigned long)page); return count;}static int fr_exit(struct net_device *dev) { struct comx_channel *ch = dev->priv; struct fr_data *fr = ch->LINE_privdata; struct net_device *sdev = dev; struct comx_channel *sch; struct fr_data *sfr; struct proc_dir_entry *dir = ch->procdir->parent->subdir; /* Ha lezarunk egy master-t, le kell kattintani a slave-eket is */ if (fr->master && fr->master == dev) { for (; dir ; dir = dir->next) { if(!S_ISDIR(dir->mode)) { continue; } if ((sdev = dir->data) && (sch = sdev->priv) && (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) && (sfr->master == dev)) { dev_close(sdev); sfr->master = NULL; } } } dev->flags = 0; dev->type = 0; dev->mtu = 0; dev->hard_header_len = 0; ch->LINE_rx = NULL; ch->LINE_tx = NULL; ch->LINE_status = NULL; ch->LINE_open = NULL; ch->LINE_close = NULL; ch->LINE_xmit = NULL; ch->LINE_header = NULL; ch->LINE_rebuild_header = NULL; ch->LINE_statistics = NULL; ch->LINE_status = 0; if (fr->master != dev) { // if not master, remove dlci if(fr->master) dev_put(fr->master); remove_proc_entry(FILENAME_DLCI, ch->procdir); remove_proc_entry(FILENAME_MASTER, ch->procdir); } else { if (fr->keepa_freq) { fr_set_keepalive(dev, 0); } remove_proc_entry(FILENAME_KEEPALIVE, ch->procdir); remove_proc_entry(FILENAME_DLCI, ch->procdir); } kfree(fr); ch->LINE_privdata = NULL; MOD_DEC_USE_COUNT; return 0;}static int fr_master_init(struct net_device *dev){ struct comx_channel *ch = dev->priv; struct fr_data *fr; struct proc_dir_entry *new_file; if ((fr = ch->LINE_privdata = kmalloc(sizeof(struct fr_data), GFP_KERNEL)) == NULL) { return -ENOMEM; } memset(fr, 0, sizeof(struct fr_data)); fr->master = dev; // this means master fr->dlci = 0; // let's say default dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; dev->type = ARPHRD_FRAD; dev->mtu = 1500; dev->hard_header_len = 4; dev->addr_len = 0; ch->LINE_rx = fr_rx; ch->LINE_tx = fr_tx; ch->LINE_status = fr_status; ch->LINE_open = fr_open; ch->LINE_close = fr_close; ch->LINE_xmit = fr_xmit; ch->LINE_header = fr_header; ch->LINE_rebuild_header = NULL; ch->LINE_statistics = fr_statistics; if ((new_file = create_proc_entry(FILENAME_DLCI, S_IFREG | 0644, ch->procdir)) == NULL) { goto cleanup_LINE_privdata; } new_file->data = (void *)new_file; new_file->read_proc = &fr_read_proc; new_file->write_proc = &fr_write_proc; new_file->size = 5; new_file->nlink = 1; if ((new_file = create_proc_entry(FILENAME_KEEPALIVE, S_IFREG | 0644, ch->procdir)) == NULL) { goto cleanup_filename_dlci; } new_file->data = (void *)new_file; new_file->read_proc = &fr_read_proc; new_file->write_proc = &fr_write_proc; new_file->size = 4; new_file->nlink = 1; fr_set_keepalive(dev, 0); MOD_INC_USE_COUNT; return 0;cleanup_filename_dlci: remove_proc_entry(FILENAME_DLCI, ch->procdir);cleanup_LINE_privdata: kfree(fr); return -EIO;}static int fr_slave_init(struct net_device *dev){ struct comx_channel *ch = dev->priv; struct fr_data *fr; struct proc_dir_entry *new_file; if ((fr = ch->LINE_privdata = kmalloc(sizeof(struct fr_data), GFP_KERNEL)) == NULL) { return -ENOMEM; } memset(fr, 0, sizeof(struct fr_data)); dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; dev->type = ARPHRD_DLCI; dev->mtu = 1500; dev->hard_header_len = 4; dev->addr_len = 0; ch->LINE_rx = fr_rx; ch->LINE_tx = fr_tx; ch->LINE_status = fr_status; ch->LINE_open = fr_open; ch->LINE_close = fr_close; ch->LINE_xmit = fr_xmit; ch->LINE_header = fr_header; ch->LINE_rebuild_header = NULL; ch->LINE_statistics = fr_statistics; if ((new_file = create_proc_entry(FILENAME_DLCI, S_IFREG | 0644, ch->procdir)) == NULL) { goto cleanup_LINE_privdata; } new_file->data = (void *)new_file; new_file->read_proc = &fr_read_proc; new_file->write_proc = &fr_write_proc; new_file->size = 5; new_file->nlink = 1; if ((new_file = create_proc_entry(FILENAME_MASTER, S_IFREG | 0644, ch->procdir)) == NULL) { goto cleanup_filename_dlci; } new_file->data = (void *)new_file; new_file->read_proc = &fr_read_proc; new_file->write_proc = &fr_write_proc; new_file->size = 10; new_file->nlink = 1; MOD_INC_USE_COUNT; return 0;cleanup_filename_dlci: remove_proc_entry(FILENAME_DLCI, ch->procdir);cleanup_LINE_privdata: kfree(fr); return -EIO;}static int dlci_open(struct net_device *dev){ struct comx_channel *ch = dev->priv; ch->init_status |= HW_OPEN; MOD_INC_USE_COUNT; return 0;}static int dlci_close(struct net_device *dev){ struct comx_channel *ch = dev->priv; ch->init_status &= ~HW_OPEN; MOD_DEC_USE_COUNT; return 0;}static int dlci_txe(struct net_device *dev){ struct comx_channel *ch = dev->priv; struct fr_data *fr = ch->LINE_privdata; if (!fr->master) { return 0; } ch = fr->master->priv; fr = ch->LINE_privdata; return ch->HW_txe(fr->master);}static int dlci_statistics(struct net_device *dev, char *page) { return 0;}static int dlci_init(struct net_device *dev){ struct comx_channel *ch = dev->priv; ch->HW_open = dlci_open; ch->HW_close = dlci_close; ch->HW_txe = dlci_txe; ch->HW_statistics = dlci_statistics; /* Nincs egyeb hw info, mert ugyis a fr->master-bol fog minden kiderulni */ MOD_INC_USE_COUNT; return 0;}static int dlci_exit(struct net_device *dev){ struct comx_channel *ch = dev->priv; ch->HW_open = NULL; ch->HW_close = NULL; ch->HW_txe = NULL; ch->HW_statistics = NULL; MOD_DEC_USE_COUNT; return 0;}static int dlci_dump(struct net_device *dev){ printk(KERN_INFO "dlci_dump %s, HOGY MI ???\n", dev->name); return -1;}static struct comx_protocol fr_master_protocol = { name: "frad", version: VERSION, encap_type: ARPHRD_FRAD, line_init: fr_master_init, line_exit: fr_exit, };static struct comx_protocol fr_slave_protocol = { name: "ietf-ip", version: VERSION, encap_type: ARPHRD_DLCI, line_init: fr_slave_init, line_exit: fr_exit, };static struct comx_hardware fr_dlci = { name: "dlci", version: VERSION, hw_init: dlci_init, hw_exit: dlci_exit, hw_dump: dlci_dump, };#ifdef MODULE#define comx_proto_fr_init init_module#endifint __init comx_proto_fr_init(void){ int ret; if ((ret = comx_register_hardware(&fr_dlci))) { return ret; } if ((ret = comx_register_protocol(&fr_master_protocol))) { return ret; } return comx_register_protocol(&fr_slave_protocol);}#ifdef MODULEvoid cleanup_module(void){ comx_unregister_hardware(fr_dlci.name); comx_unregister_protocol(fr_master_protocol.name); comx_unregister_protocol(fr_slave_protocol.name);}#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -