#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <sys/ioctl.h> #include <string.h> #include <syslog.h> #include <fcntl.h> #include <signal.h> #include "atm.h" #include <linux/atmdev.h> #include <linux/atmbr2684.h> #include <linux/autoconf.h> #ifdef CONFIG_ATM_CLIP // Jenny, for IPoA #include <linux/atmclip.h> #include <linux/atmarp.h> #endif #include "rtk/options.h" /* Written by Marcell GAL <cell@sch.bme.hu> to make use of the */ /* ioctls defined in the br2684... kernel patch */ /* Compile with cc -o br2684ctl br2684ctl.c -latm */ /* Modified feb 2001 by Stephen Aaskov (saa@lasat.com) - Added daemonization code - Added syslog TODO: Delete interfaces after exit? */ #define LOG_NAME "RFC1483/2684 bridge" #define LOG_OPTION LOG_PERROR #define LOG_FACILITY LOG_LOCAL0 #define DEV_NAME "vc" /* * 0: VC_BR * 1: LLC_BR * 3: VC_RT * 4: LLC_RT */ int my_encaps; struct mpoa_cfg { struct mpoa_cfg *prev; struct mpoa_cfg *next; int sock; char ifname[IFNAMSIZ]; int encaps; struct sockaddr_atmpvc addr; struct atm_qos qos; //#ifdef CONFIG_RE8305 // vlan tagging struct vlan vlan_tag; // interface group struct itfgrp ifgrp; #ifdef NEW_PORTMAPPING uint16_t fgroup; #endif //#endif #ifdef CONFIG_ATM_CLIP unsigned long clip_ip; // Jenny, ipoa host ip unsigned long srv_ip; // Jenny, ipoa arp server ip #endif }; struct command { int needs_mpoa_arg; int num_string_arg; char *name; int (*func)(struct mpoa_cfg *cfg, char *arg); }; #define SERVER_FIFO_NAME "/tmp/serv_fifo" #define CLIENT_FIFO_NAME "/tmp/cli_fifo" #define BUFFER_SIZE 256 struct data_to_pass_st { int id; char data[BUFFER_SIZE]; }; struct mpoa_cfg *cfg_head = NULL; int lastsock, lastitf; static char *qosstr = NULL; void fatal(char *str, int i) { syslog (LOG_ERR,"Fatal: %s",str); exit(-2); }; void exitFunc(void) { syslog (LOG_PID,"Daemon terminated\n"); } struct mpoa_cfg * find_cfg_ptr(char *arg) { struct mpoa_cfg *cfg; if(cfg_head == NULL) return NULL; else { cfg = cfg_head; do { if(!strcmp(cfg->ifname, arg)) return cfg; cfg = cfg->next; } while(cfg); return NULL; } } int show_if(struct mpoa_cfg *cfg, char *arg) { #ifdef CONFIG_ATM_CLIP // Jenny, for IPoA char *encaps_str[] = {"BR1483 VCMUX", "BR1483 LLC", "BR1483 AUTO", "RT1483 VCMUX", "RT1483 LLC", "RT1483 AUTO", "RT1577 LLC" }; #else char *encaps_str[] = {"BR1483 VCMUX", "BR1483 LLC", "BR1483 AUTO", "RT1483 VCMUX", "RT1483 LLC", "RT1483 AUTO" }; #endif char *qos_str[] = {"none", "UBR", "CBR", "VBR"}; char *aal_str[] = {"AAL0", "AAL5"}; cfg = cfg_head; while(cfg) { printf("%s\t%d.%d %s %s\n", cfg->ifname, cfg->addr.sap_addr.vpi, cfg->addr.sap_addr.vci, (cfg->qos.aal == ATM_AAL0) ? aal_str[0]: aal_str[1], encaps_str[cfg->encaps]); printf("\t%s PCR = %d SCR = %d MBS = %d\n\n", qos_str[cfg->qos.txtp.traffic_class], cfg->qos.txtp.pcr, cfg->qos.txtp.scr, cfg->qos.txtp.mbs); cfg = cfg->next; } return 0; } #ifdef CONFIG_ATM_CLIP int create_clip(struct mpoa_cfg *cfg, char *arg) // Jenny, create IPoA interface { int num, err; unsigned int number; struct mpoa_cfg *new_cfg; if((new_cfg = malloc(sizeof(struct mpoa_cfg)))==NULL) return -1; new_cfg->sock = socket(PF_ATMPVC, SOCK_DGRAM, ATM_AAL5); if(new_cfg->sock < 0) { free(new_cfg); return -1; } strcpy(new_cfg->ifname, arg); sscanf(new_cfg->ifname, "vc%u", &number); num = ioctl (new_cfg->sock, SIOCMKCLIP, number); if (num >= 0) { if(cfg_head == NULL) { cfg = cfg_head = new_cfg; cfg->prev = NULL; cfg->next = NULL; } else { cfg = cfg_head; while(cfg->next!=NULL) cfg = cfg->next; cfg->next = new_cfg; new_cfg->prev = cfg; new_cfg->next = NULL; cfg = new_cfg; } syslog(LOG_INFO, "Interface \"%s\" created sucessfully\n", cfg->ifname); } else { syslog(LOG_INFO, "Interface \"%s\" could not be created, reason: %s\n", new_cfg->ifname, strerror(errno)); close(new_cfg->sock); free(new_cfg); } return 0; } #endif int create_if(struct mpoa_cfg *cfg, char *arg) { int num, err; struct mpoa_cfg *new_cfg; if((new_cfg = malloc(sizeof(struct mpoa_cfg)))==NULL) return -1; new_cfg->sock = socket(PF_ATMPVC, SOCK_DGRAM, ATM_AAL5); if(new_cfg->sock < 0) { free(new_cfg); return -1; } strcpy(new_cfg->ifname, arg); /* create the device with ioctl: */ //num=atoi(arg); //if( num>=0 && num<16) { struct atm_newif_br2684 ni; ni.backend_num = ATM_BACKEND_BR2684; #ifdef _LINUX_2_6_ ni.media = BR2684_MEDIA_ETHERNET; #else if (my_encaps == 0 || my_encaps == 1) // Bridge mode ni.media = BR2684_MEDIA_ETHERNET; else // Routing mode ni.media = BR2684_FLAG_ROUTED; #endif ni.mtu = 1500; //sprintf(ni.ifname, "%s%d", DEV_NAME, num); strcpy(ni.ifname, new_cfg->ifname); err=ioctl (new_cfg->sock, ATM_NEWBACKENDIF, &ni); if (err == 0) { if(cfg_head == NULL) { cfg = cfg_head = new_cfg; cfg->prev = NULL; cfg->next = NULL; } else { cfg = cfg_head; while(cfg->next!=NULL) cfg = cfg->next; cfg->next = new_cfg; new_cfg->prev = cfg; new_cfg->next = NULL; cfg = new_cfg; } syslog(LOG_INFO, "Interface \"%s\" created sucessfully\n",ni.ifname); } else { close(new_cfg->sock); free(new_cfg); syslog(LOG_INFO, "Interface \"%s\" could not be created, reason: %s\n", ni.ifname, strerror(errno)); return -1; } } //else { // syslog(LOG_ERR,"err: strange interface number %d", num ); //} return 0; } int delete_if(struct mpoa_cfg *cfg, char *arg) { /* find new cfg instance */ cfg = cfg_head; while (cfg != NULL) { if(!strcmp(cfg->ifname, arg)) break; cfg = cfg->next; }; if(cfg==NULL) return -1; close(cfg->sock); if(cfg->next) cfg->next->prev = cfg->prev; if(cfg->prev) cfg->prev->next = cfg->next; else cfg_head = cfg->next; free(cfg); return 0; } int set_encaps(struct mpoa_cfg *cfg, char *arg) { if(cfg==NULL) return -1; cfg->encaps = atoi(arg); #ifndef _LINUX_2_6_ if (cfg->encaps == 0 || cfg->encaps == 3) cfg->encaps = 0; // VC else if (cfg->encaps == 1 || cfg->encaps == 4) cfg->encaps = 1; // LLC #endif return 0; } int set_qos(struct mpoa_cfg *cfg, char *arg) { int err, errno; int sndbuf = 8192; if(cfg==NULL) return -1; memset(&cfg->qos, 0, sizeof(struct atm_qos)); if (arg != NULL){ if (text2qos(arg, &cfg->qos, 0)){ printf("Can't parse QoS: %s \n", arg); return -1; } } if(!cfg->qos.aal) cfg->qos.aal = ATM_AAL5; if(!cfg->qos.txtp.traffic_class) cfg->qos.txtp.traffic_class = ATM_UBR; if(!cfg->qos.txtp.pcr) cfg->qos.txtp.pcr = 0x1DFF; cfg->qos.txtp.max_sdu = 1524; cfg->qos.rxtp = cfg->qos.txtp; if ( (err=setsockopt(cfg->sock,SOL_SOCKET,SO_SNDBUF, &sndbuf ,sizeof(sndbuf))) ){ syslog(LOG_ERR,"setsockopt SO_SNDBUF: (%d) %s\n",err, strerror(err)); return -1; } if ( setsockopt(cfg->sock, SOL_ATM, SO_ATMQOS, &cfg->qos, sizeof(struct atm_qos)) < 0){ syslog(LOG_ERR,"setsockopt SO_ATMQOS: %d\n", errno); return -1; } return 0; } int assign_vcc(struct mpoa_cfg *cfg, char *arg) { int err, errno; int fd; struct atm_backend_br2684 be; if(cfg==NULL) return -1; memset(&cfg->addr, 0, sizeof(struct sockaddr_atmpvc)); err=text2atm(arg,(struct sockaddr *)(&cfg->addr), sizeof(struct sockaddr_atmpvc), T2A_PVC); if (err!=0){ syslog(LOG_ERR,"Could not parse ATM parameters (error=%d)\n",err); return -1; } syslog(LOG_INFO,"Communicating over ATM %d.%d.%d, encapsulation: %d\n", cfg->addr.sap_addr.itf, cfg->addr.sap_addr.vpi, cfg->addr.sap_addr.vci, cfg->encaps); if(cfg->qos.aal == 0){ err = set_qos(cfg, "ubr"); if (err!=0) return -1; } err = connect(cfg->sock, (struct sockaddr*)&cfg->addr, sizeof(struct sockaddr_atmpvc)); if (err < 0) { syslog (LOG_ERR,"failed to connect on socket"); return -1; } /* attach the vcc to device: */ #ifdef CONFIG_ATM_CLIP // Jenny, for IPoA if (cfg->encaps == 6) { if (ioctl(cfg->sock, ATMARP_MKIP, CLIP_DEFAULT_AGINGTIMER) < 0) { err = -errno; syslog (LOG_ERR, "ioctl ATMARP_MKIP: %s", strerror(errno)); return -1; } else syslog (LOG_INFO,"Interface configured"); } else { #endif be.backend_num = ATM_BACKEND_BR2684; be.ifspec.method = BR2684_FIND_BYIFNAME; //sprintf(be.ifspec.spec.ifname, "%s%d", DEV_NAME, lastitf); strcpy(be.ifspec.spec.ifname, cfg->ifname); be.fcs_in = BR2684_FCSIN_NO; be.fcs_out = BR2684_FCSOUT_NO; be.fcs_auto = 0; be.encaps = cfg->encaps; be.has_vpiid = 0; be.send_padding = 0; be.min_size = 0; err=ioctl (cfg->sock, ATM_SETBACKEND, &be); if (err == 0) syslog (LOG_INFO,"Interface configured"); else { syslog (LOG_ERR,"Could not configure interface:%s",strerror(errno)); return -1; } #ifdef CONFIG_ATM_CLIP } #endif return 0 ; } //#ifdef CONFIG_RE8305 // Vlan tagging int set_vid(struct mpoa_cfg *cfg, char *arg) { if(cfg==NULL) return -1; cfg->vlan_tag.vid = atoi(arg); return 0; } int set_vprio(struct mpoa_cfg *cfg, char *arg) { if(cfg==NULL) return -1; cfg->vlan_tag.vlan_prio = atoi(arg); return 0; } int set_vpass(struct mpoa_cfg *cfg, char *arg) { if(cfg==NULL) return -1; cfg->vlan_tag.vlan_pass = atoi(arg); return 0; } int assign_vlan(struct mpoa_cfg *cfg, char *arg) { int err; int fd; struct atm_backend_br2684 be; if(cfg==NULL) return -1; cfg->vlan_tag.vlan = atoi(arg); //printf("assign_vlan: vlan=%d, vid=%d, vprio=%d, vpass=%d\n", cfg->vlan_tag.vlan, cfg->vlan_tag.vid, cfg->vlan_tag.vprio, cfg->vlan_tag.vpass); be.ifspec.method = BR2684_FIND_BYIFNAME; strcpy(be.ifspec.spec.ifname, cfg->ifname); be.vlan_tag.vlan = cfg->vlan_tag.vlan; be.vlan_tag.vid = cfg->vlan_tag.vid; be.vlan_tag.vlan_prio = cfg->vlan_tag.vlan_prio; be.vlan_tag.vlan_pass = cfg->vlan_tag.vlan_pass; err=ioctl (cfg->sock, ATM_SETVLAN, &be); if (err!=0) return -1; return 0; } // Interface Group int set_member(struct mpoa_cfg *cfg, char *arg) { if(cfg==NULL) return -1; cfg->ifgrp.member = atoi(arg); return 0; } int assign_group(struct mpoa_cfg *cfg, char *arg) { int err; int fd; struct atm_backend_br2684 be; if(cfg==NULL) return -1; cfg->ifgrp.flag = atoi(arg); be.ifspec.method = BR2684_FIND_BYIFNAME; strcpy(be.ifspec.spec.ifname, cfg->ifname); memcpy(&be.ifgrp, &cfg->ifgrp, sizeof(struct itfgrp)); //printf("assign_group: group=%d, member=0x%x\n", be.ifgrp.flag, be.ifgrp.member); err=ioctl (cfg->sock, ATM_SETITFGRP, &be); if (err!=0) return -1; return 0; } //#endif #ifdef CONFIG_ATM_CLIP // Jenny, for IPoA int init_atmarp(struct mpoa_cfg *cfg, char *arg) // Jenny, init atm arpd { if(cfg==NULL) { printf("init_atmarp: cfg=NULL\n"); return -1; } if (ioctl(cfg->sock, ATMARPD_CTRL, 0) < 0) { syslog(LOG_ERR, "ioctl ATMARPD_CTRL: %s", strerror(errno)); return -1; } else syslog (LOG_INFO,"atmarp init"); return 0; } int set_ip(struct mpoa_cfg *cfg, char *arg) // Jenny, set ipoa local host ip { char *endptr; if(cfg==NULL) return -1; cfg->clip_ip = strtoul(arg, &endptr, 0); if (ioctl(cfg->sock, ATMARP_IP, cfg->clip_ip) < 0) { syslog(LOG_ERR, "ioctl ATMARP_IP: %s", strerror(errno)); return -1; } else syslog (LOG_INFO,"atmarp set_ip"); return 0; } int send_inARPRep(struct mpoa_cfg *cfg, char *arg) // Jenny, send inATMARP Reply { char *endptr; if (cfg == NULL) return -1; cfg->srv_ip = strtoul(arg, &endptr, 0); if (ioctl(cfg->sock, ATMARP_INARPREP, cfg->srv_ip) < 0) { syslog(LOG_ERR, "ioctl ATMARP_INARPREP: %s", strerror(errno)); } else syslog (LOG_INFO,"atmarp send_inARPRep"); return 0; } /* int set_srv(struct mpoa_cfg *cfg, char *arg) // Jenny, set ipoa atm arp server ip { char *endptr; if(cfg==NULL) return -1; cfg->srv_ip = strtoul(arg, &endptr, 0); if (ioctl(cfg->sock, ATMARP_SRV, cfg->srv_ip) < 0) { syslog(LOG_ERR, "ioctl ATMARP_IP: %s", strerror(errno)); exit(2); } else syslog (LOG_INFO,"atmarp set_srv"); return 0; }*/ #endif #ifdef NEW_PORTMAPPING int set_fgroup(struct mpoa_cfg *cfg, char *arg) { int err; int fd; struct atm_backend_br2684 be; if(cfg==NULL) return -1; cfg->fgroup = (uint16_t)atoi(arg); be.ifspec.method = BR2684_FIND_BYIFNAME; strcpy(be.ifspec.spec.ifname, cfg->ifname); //we just consider the switch lan port, //put away the wlan be.fgroup = (uint16_t)(cfg->fgroup & 0x1ff); err=ioctl (cfg->sock, ATM_SETFGROUP, &be); if (err!=0) return -1; return 0; } #endif /*----------------------------------------------------------------- * usage: * mpoactl add vc0 pvc 0.33 encaps 1 qos ubr:pcr=7600 * mpoactl set vc0 vlan 1 vid 23 vprio 2 vpass 0 *----------------------------------------------------------------*/ static struct command commands[] = { {0, 1, "show", show_if}, #ifdef CONFIG_ATM_CLIP {0, 1, "addclip", create_clip}, // Jenny, create IPoA interface #endif {0, 1, "add", create_if}, {0, 0, "set", 0}, {1, 1, "del", delete_if}, {1, 1, "encaps", set_encaps}, {1, 1, "qos", set_qos}, {1, 1, "pvc", assign_vcc}, //#ifdef CONFIG_RE8305 // vlan tagging {1, 1, "vid", set_vid}, {1, 1, "vprio", set_vprio}, {1, 1, "vpass", set_vpass}, {1, 1, "vlan", assign_vlan}, // interface group {1, 1, "member", set_member}, {1, 1, "group", assign_group}, #ifdef NEW_PORTMAPPING {1, 1, "fgroup", set_fgroup}, #endif //#endif #ifdef CONFIG_ATM_CLIP {1, 1, "atmarp", init_atmarp}, // Jenny, init atm arpd {1, 1, "cip", set_ip}, // Jenny, set ipoa client ip {1, 1, "inarprep", send_inARPRep}, // Jenny, send inATMARP Reply // {1, 1, "sip", set_srv}, // Jenny, set ipoa atm arp server ip // {1, 1, "entry", set_entry}, #endif {0, 0, NULL, NULL} }; struct command *mpoa_command_lookup(char *arg) { int i; for(i=0; commands[i].name!=NULL; i++) if(!strcmp(arg, commands[i].name)) return (&commands[i]); return NULL; } void usage(char *s) { printf("usage: %s [-b] [[-c number] [-e 0|1] [-a [itf.]vpi.vci]*]*\n", s); exit(1); } #define MAX_ARGS 20 #define MAX_ARG_LEN 50 #ifdef EMBED static char mpoad_pidfile[] = "/var/run/mpoad.pid"; static void log_pid() { FILE *f; pid_t pid; char *pidfile = mpoad_pidfile; pid = getpid(); if((f = fopen(pidfile, "w")) == NULL) return; fprintf(f, "%d\n", pid); fclose(f); } static void quit_signal(int sig) { unlink(SERVER_FIFO_NAME); unlink(mpoad_pidfile); exit(1); } #endif #ifdef _LINUX_2_6_ // Use this would cause busy waitting. Should it be removed ? //#define _MPOA_NOT_CLOSE_FD_ #endif //_LINUX_2_6_ int main (void) { int server_fifo_fd, client_fifo_fd; struct data_to_pass_st msg; int read_res; int i, c, err=0; int argc; char argv[MAX_ARGS][MAX_ARG_LEN+1]; char *arg_ptr; struct mpoa_cfg *cfg; lastsock=-1; lastitf=0; mkfifo(SERVER_FIFO_NAME, 0777); syslog (LOG_INFO, "RFC 1483/2684 bridge daemon started\n"); #ifdef EMBED signal (SIGTERM, quit_signal); signal (SIGSEGV, quit_signal); log_pid(); #endif while (1) { server_fifo_fd = open(SERVER_FIFO_NAME, O_RDONLY); if (server_fifo_fd == -1) { fprintf(stderr, "Server fifo failure\n"); exit(EXIT_FAILURE); } #ifdef _MPOA_NOT_CLOSE_FD_ read_again: #endif //_MPOA_NOT_CLOSE_FD_ argc = 0; //jiunming, this may be an unnecessary do{}while loop //if read for the second time, use the same buffer as one for the first time //note: for 8672, it occurs that 2 commands may be read in the do{} while loop. //do { read_res = read(server_fifo_fd, &msg, sizeof(msg)); if(read_res > 0) { int arg_idx = 0; arg_ptr = msg.data; for(i=0; arg_ptr[i]!='\0'; i++) { if(arg_ptr[i]==' '){ argv[argc][arg_idx]='\0'; argc++; arg_idx=0; } else { if(arg_idx<MAX_ARG_LEN) { argv[argc][arg_idx]=arg_ptr[i]; arg_idx++; } } } argv[argc][arg_idx]='\0'; } //} while (read_res > 0); #ifndef _MPOA_NOT_CLOSE_FD_ close(server_fifo_fd); #endif //_MPOA_NOT_CLOSE_FD_ cfg = NULL; #ifndef _LINUX_2_6_ // get encaps for(i=1; i<argc; i++) { if(!strcmp(argv[i], "encaps")) { my_encaps = atoi(argv[i+1]); printf("my_encaps=%d\n", my_encaps); } } #endif for(c=0; commands[c].name!=NULL; c++) { for(i=1; i<argc; i++) { if(!strcmp(argv[i], commands[c].name)) { if(!cfg) if(commands[c].needs_mpoa_arg) cfg = find_cfg_ptr(argv[2]); if(commands[c].num_string_arg) { err = commands[c].func(cfg, argv[i+1]); if (err!=0) break; if (!cfg) break; } } } } #ifdef _MPOA_NOT_CLOSE_FD_ goto read_again; #endif //_MPOA_NOT_CLOSE_FD_ } #ifdef EMBED unlink(mpoad_pidfile); #endif atexit (exitFunc); return 0; }