From: Jon M. <jon...@er...> - 2003-12-09 21:06:16
|
I think there it is time for a small upgrade of TIPC now. I have been extremely conservative with adding new features to the TIPC tar-balls, because I had a feeling its quality was deteriorating for a while. Now I think it is ok. I don't have time to do this right now, so I would be happy if one of you (J-G) would do the following: 1) Download tipc-1.2.03 2) Check out the latest "stable_ericsson". 3) Merge Guo's multicast functionality from ericsson_stable (Multicast.c and new contents of NameTable.c) into tipc-1.2.03. But NOT Ling's additions to Reference.c and other files. (Sorry, Ling, but we can only do this in one way, and I prefer the distributed solution.) 4) Change to BSD licence even in tipc.h, a file I forgot to update. 5) Test the whole thing, with the benchmark, and with Vincent's and Guo's test suites. 6) Check into CVS. 7) Tell me, and I will make a tar-ball of it and put it up at SF. /jon Jean-Guillaume wrote: Jon: please include the following tipc_start.c file in the next stable versions of tipc, I was surprised to see that it still doesn't include the modications to start the procfs! I must have forgotten to send you the modified file. Also, I did a very minor change (removed a useless printk, and something else), so this is the new version to be included with 1.2.03. To the others: I have changed proc_adaptation so that it uses procfs instead of seqfile, and I changed some functions, so that the code now takes half the lines it used to. It is now 2100 lines, and it will get tough to go lower than that, because there is a good number of functiosn associated to the maintenance of the dynamic procfs. Please try this new version with the 1.2.03 version of tipc (and the tipc_start.c file given here). I am curious to see if you will still get crashes when doing a "cat nametable" ?? like I said in my previous mail, we won't use /proc/sys for now, because of the dynamic updates. add the -DDYNAMIC_PROC flag to use the name subscription (no more scannetwork file) thanks J-G _____ /* * proc_adaptation.c: Creates and manage the /proc/tipc directory, which displays information from kernel memory. Created 2003-09-15 by Jean-Guillaume Paradis, intern at Ericsson Canada, Montreal */ /****************************************************************** Copyright (c) 2003, Ericsson Research Canada All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of Ericsson Research Canada nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************/ #include <linux/kernel.h> #include <linux/init.h> #include <linux/proc_fs.h> #include <linux/stat.h> #include <linux/string.h> #include <linux/seq_file.h> #include <linux/poll.h> #include <linux/dirent.h> #include <linux/list.h> #include <linux/sysctl.h> #include <stdio.h> #include <tipc.h> #include <tipc_adaptation.h> #include "tipc_port.h" #include "tipc_adaptation_locks.h" #define DEBUG_LEVEL 0 #define TIPC_DIR "tipc" #define MOD_NAME "proc_adapt: " #define printf0(args...) if(DEBUG_LEVEL >= 0) { printk(args); } #define printf1(args...) if(DEBUG_LEVEL >= 1) { printk(args); } #define printf2(args...) if(DEBUG_LEVEL >= 2) { printk(args); } #define printf3(args...) if(DEBUG_LEVEL >= 3) { printk(args); } #define LINKS_CREATION 1 #define PORTS_CREATION 2 #define BEARERS_CREATION 3 extern const char *addr_string(tipc_address_t); extern boolean bearer_nameValid(const char *); /*************************** Used for the proc files ****************************/ #define NUMS_SIZE 5 #define MAX_ZONES 15 #define MAX_PROCS_BY_SUBNET 512 #define MAX_PROCS_ON_NETWORK 7680 #define MAX_LINK_BY_PROC 4 #define LINK_NAME_LENGTH 72 #define MAX_PORTS 2048 //to check #define MAX_BEARER_TYPES 10 #define MAX_BEARER_NAMES 10 //used for the waitQueues array, the numbers correspond to the index // the queues array must be big enough to handle all the types, of course #define PROCESSORS_TYPE 0 #define LINKS_TYPE 1 #define LINK_STATS_TYPE 2 #define RESET_LINK_TYPE 3 #define ROUTING_TABLE_TYPE 4 #define PEER_ADDRESS_TYPE 5 #define PORTS_TYPE 6 #define PORT_STATS_TYPE 7 #define RESET_PORT_STATS_TYPE 8 #define BEARERS_TYPE 9 #define NAME_TABLE_TYPE 10 #define SECOND_COMMAND_GROUP_TYPE 11 #define CREATE_LINK_TYPE 12 #define REMOVE_LINK_TYPE 13 #define BLOCK_LINK_TYPE 14 #define UNBLOCK_LINK_TYPE 15 #define SET_LINK_TOLERANCE_TYPE 16 #define SET_LINK_PRIORITY_TYPE 17 #define SET_LINK_WINDOW_TYPE 18 #define ENABLE_BEARER_TYPE 19 #define DISABLE_BEARER_TYPE 20 #define PROC_NA_TYPE 21 #define OWN_ADDRESS_TYPE 22 #define SCAN_NETWORK_TYPE 23 struct proc_dir_entry *tipc_root; struct proc_dir_entry *tipc_sys_net; struct ctl_table_header *tipc_sys_dir; struct proc_file_info { int type; struct proc_dir_entry *this; }; struct parent_proc_info { uint proc_addr; int proc_index; }; // Used to store the links of a processor, for cleaning of the procfs struct link_name { char name[LINK_NAME_LENGTH]; // int nb; struct list_head next; }; struct generic_proc_entry { //used for port names, char name[20]; struct list_head next; }; struct proc_entry_with_dir { //user for bearer types, bearers char name[20]; struct proc_dir_entry *dir; //the bearerType keeps its own proc_dir_entry, bearers names keep the proc_dir_entry of //their parent (a bearerType) struct list_head next; }; struct subnet_dir_entry { struct proc_dir_entry *this; struct proc_dir_entry *parent; }; struct my_proc_dir_entry { int exists; int available; struct proc_dir_entry *this; struct proc_dir_entry *parent; struct proc_dir_entry *links_dir; // processor1->Links directory struct proc_dir_entry *ports_dir; struct proc_dir_entry *bearers_dir; //we must keep the names of the directories created, to remove the entries when necessary struct list_head list_bearer_types; struct list_head list_bearer_names; struct list_head list_links; struct list_head list_ports; struct link_name *links[MAX_PROCS_BY_SUBNET * MAX_LINK_BY_PROC]; //the names are kept here, and are linked with the above lists struct generic_proc_entry *ports[MAX_PORTS]; struct proc_entry_with_dir *bearer_types[MAX_BEARER_TYPES]; struct proc_entry_with_dir *bearer_names[MAX_BEARER_NAMES]; }; //when doign a request to the manager, these queues wait for the callBack function when necessary static wait_queue_head_t queues[30]; //these are the entries in /proc/tipc, we must remove them at module exit to avoid corruption of the procfs static struct proc_dir_entry *own_address_dir, *processors, *network_dir, *scan_network; //static struct proc_dir_entry * routingTableDir; not implemented yet, add it if it is one day //We set these variables to 1 in the corresponding callBack-> they are the tested condition //to wakeup the waiting queue //After the wakeup, we set them back to 0, waiting for the next request static int get_processors_cb_done = 0, get_links_cb_done = 0, get_link_stats_cb_done = 0; static int get_peer_address_cb_done = 0, reset_link_stats_cb_done = 0, get_ports_cb_done = 0, get_port_stats_cb_done = 0; static int reset_port_stats_cb_done = 0, get_name_table_cb_done = 0, get_bearers_cb_done = 0; //The second group of commands share the same callback static int second_cmd_group_cb_done = 0; static int nb_procs = 0, nb_links = 0, nb_ports = 0; //these are used in the creation of the procs directory hierarchy, to keep track of the existing zones, etc. static int zones[MAX_ZONES] = { 0, }; static struct subnet_dir_entry *subnets[MAX_ZONES]; /* the procs struct uses the "proc_index" , which is mentionned in some conversion functions */ static struct my_proc_dir_entry *procs[MAX_PROCS_ON_NETWORK]; //keeps the result of the CallBack until the Show method of the procfile char result_links_cb[1], result_link_stats_cb[1], result_ports_cb[1]; //char * result_port_stats_cb; Doing a dynamic allocation doesn't work here //the string is ok in all functions, until we hit the get_portsStats_start, show etc //There, the string is missing a part! // There are NO places except in the callback where the value of the string is changed.. //weird... another procfs trick. //let use these arrays for now... char result_bearers_cb[1], result_port_stats_cb[1], result_name_table_cb[1], result_routing_table_cb[1]; char result_peer_address_cb[64]; //char * result_name_table_cb; // once again, problems with dynamic allocation... when using this variable, with //malloc in the callback and free in the get_name_table_stop procfs function, //we get a segmentation fault -> unable to handle kernel paging request, //but this error occurs AFTER the unloading of my module!!! //seems like there are a couple of fishy things in the procfs... //(I'm not surprised, somebody in the linux kernel mailing list told me the procfs //was pretty messed up ):( //Each of these function needs its own port to the manager static tipc_id_t port_id_processor = 0, port_id_bearers = 0, port_id_links = 0, port_id_link_stats = 0; static tipc_id_t port_id_peer_address = 0, port_id_reset_link_stats = 0, port_id_name_table = 0, port_id_id_ports = 0; static tipc_id_t port_id_port_stats = 0, port_id_reset_stats = 0; static tipc_id_t user = 0; //second command group share the same port static tipc_id_t port_id_second_cmd_group = 0; //holds the ports number after a get_ports static uint ports[MAX_PORTS]; static struct tipc_createport_argv createport; static struct tipc_portname port; /**************************** Set by the CallBacks, used for the proc files *****************************/ static struct tipc_command_result_msg *get_processors_cb_result; /**************************** Function Declarations *****************************/ static int wait_for_callback(int *, int); static int addr_to_proc_nb(tipc_id_t); static tipc_id_t addr_atoi(char *); static tipc_id_t proc_nb_to_addr(int); static void add_proc_to_list(tipc_id_t, int); static void remove_proc_from_list(tipc_id_t); static void parse_string_and_action(int, int); static int proc_read_data(char *, char **, off_t, int, int *, void *); static int proc_write_data(struct file *, const char *, unsigned long, void *); static void print_manager_return_value(int, char *); static void set_proc_attributes(struct proc_dir_entry *, int); ////void free_proc_bearers(int); /************************************************* Various conversion functions **************************************************/ // atoi is in os_adaptation, but not itoa static void set_proc_attributes(struct proc_dir_entry *file, int type) { struct proc_file_info *info; file->read_proc = proc_read_data; file->data = (struct proc_file_info *) os_malloc(sizeof (struct proc_file_info)); info = file->data; info->type = type; info->this = file; } static char * itoa(uint i) { char buf[12]; char *pos = buf + sizeof (buf) - 1; unsigned int u; int negative = 0; if (i < 0) { negative = 1; u = ((unsigned int) (-(1 + i))) + 1; } else { u = i; } *pos = 0; do { *--pos = '0' + (u % 10); u /= 10; } while (u); if (negative) { *--pos = '-'; } return pos; } /* tipc address --> processorNb index for the procs array for now we don't need to work with the subnetNb, as it is the same as the zoneZb */ static int addr_to_proc_nb(tipc_id_t addr) { int zoneNb = 0xFF000000 & addr; int procNb = 0x00000FFF & addr; zoneNb = zoneNb >> 24; return ((zoneNb - 1) * MAX_PROCS_BY_SUBNET + (procNb - 1)); } /* processorNb index -> tipc address */ static tipc_id_t proc_nb_to_addr(int procNb) { tipc_id_t ret; int zone = procNb / MAX_PROCS_BY_SUBNET; zone++; int processor = procNb % MAX_PROCS_BY_SUBNET; processor++; ret = (zone << 24) + (zone << 12) + processor; return ret; } /* takes an address in the form 0.0.0 returns a number corresponding to the string address --> Maybe I might need a function that can take an address in the 0.0 form, etc */ static tipc_id_t addr_atoi(char *addr) { int zoneNb, subNb, procNb; tipc_id_t ret; char zone[6] = { 0, }; char sub[6] = { 0, }; char proc[6] = { 0, }; char *pos2; char *pos = strchr(addr, '.'); memcpy(&zone, addr, pos - addr); zoneNb = atoi(zone); pos = pos + 1; pos2 = strchr(pos, '.'); memcpy(&sub, pos, pos2 - pos); subNb = atoi(sub); pos = pos2 + 1; pos2 = strchr(pos, '\0'); memcpy(&proc, pos, pos2 - pos); procNb = atoi(proc); ret = (zoneNb << 24) + (subNb << 12) + procNb; return ret; } /************************************** Some functions to parse strings **************************************/ /* returns the number at the end of the directory name, after the _ ex: processor_2 */ static int parse_dir(const char *dir) { return atoi(dir); } static int parse_nametable(const char *dir) { char *pos = strchr(dir, '_'); return atoi(pos + 1); } //extrack the bearerType of a bearerName static char * parse_bearer_type(char *bearer) { char *pos, *ret; char type[20] = { 0, }; pos = strchr(bearer, ':'); memcpy(type, bearer + 1, pos - bearer - 1); ret = (char *) os_malloc(sizeof (type) + 1); strcpy(ret, type); return ret; } //extract the bearer's name of a bearerName //-> eth0 from <ethernet:eth0> for example static char * parse_bearer_name(char *bearer) { char *pos, *pos2; char name[20] = { 0, }; char *ret; pos = strchr(bearer, ':'); pos++; pos2 = strchr(pos, '>'); memcpy(name, pos, pos2 - pos); ret = (char *) os_malloc(sizeof (name) + 1); strcpy(ret, name); return ret; } //returned char * must be freed static char * bearer_name_from_dir(struct proc_dir_entry *file) { char name[40] = { 0 }; char type[40] = { 0 }; char *ret; int sizeName = 0, sizeType = 0; strcpy(name, file->parent->name); strcpy(type, file->parent->parent->name); sizeName = strlen(name); sizeType = strlen(type); ret = (char *) os_malloc(100); ret[0] = '<'; memcpy(&ret[1], type, sizeType); ret[sizeType + 1] = ':'; memcpy(&ret[sizeType + 2], name, sizeName); ret[sizeType + sizeName + 2] = '>'; return ret; } //level is the depth of the read file compared to the "processor_1" directory, for example static struct parent_proc_info get_parent_proc_info(struct proc_dir_entry *file, int level) { uint procNb = 0, subNb = 0, zoneNb = 0; struct parent_proc_info ret; switch (level) { case 1:{ procNb = parse_dir(file->parent->name); subNb = parse_dir(file->parent->parent->name); zoneNb = parse_dir(file->parent->parent->parent->name); break; } case 3:{ procNb = parse_dir(file->parent->parent->parent->name); subNb = parse_dir(file->parent->parent->parent->parent->name); zoneNb =parse_dir(file->parent->parent->parent->parent->parent->name); break; } case 4:{ procNb =parse_dir(file->parent->parent->parent->parent->name); subNb = parse_dir(file->parent->parent->parent->parent-> parent->name); zoneNb = parse_dir(file->parent->parent->parent->parent->parent->parent->name); break; } default:{ printk("TIPC------> Default Case of get_parent_proc_info: should not be there!\n"); break; } } ret.proc_index = (zoneNb - 1) * MAX_PROCS_BY_SUBNET + procNb - 1; ret.proc_addr = (zoneNb << 24) + (subNb << 12) + procNb; return ret; } /************************************************************* Callback functions, triggered by the functions that use the Manager (see below) Each callback needs an error_even callBack **************************************************************/ /* Handles error codes, prints the reason */ static void error_msg_code_reason(tipc_msg_error_code reason) { switch (reason) { case (tipc_no_portname): printk("TIPC------> No portname\n"); break; case (tipc_no_remote_port): printk("TIPC------> No remote port\n"); break; case (tipc_no_remote_processor): printk("TIPC------> No remote processor\n"); break; case (tipc_destination_overloaded): printk("TIPC------> Destination overload\n"); break; case (tipc_not_connected): printk("TIPC------> Not connected\n"); break; case (tipc_communication_error): printk("TIPC------> Communication error\n"); break; default: printk("TIPC------> Unspecified error\n"); break; } } /************** The first callbacks are tipc_message_event **************/ static tipc_message_event get_processors_cb(void *userdata, tipc_id_t portid, unsigned char const *data, unsigned int size, tipc_portreference const *origin, tipc_msg_importance importance, void **buf) { tipc_message_event dummy = (tipc_message_event) 0; get_processors_cb_result = (tipc_command_result_msg *) data; nb_procs = ntohl(get_processors_cb_result->result_len) / sizeof (get_processors_cb_result->result.processors[0]); get_processors_cb_done = 1; wake_up(&queues[PROCESSORS_TYPE]); return dummy; } static tipc_error_event first_cmd_group_error_cb(void *userdata, tipc_id_t portid, unsigned char const *data, unsigned int size, tipc_portreference const *attempted_dest_id, tipc_msg_error_code reason, tipc_portname const *attempted_dest_name, void **buf) { tipc_error_event dummy = (tipc_error_event) 0; printk("TIPC------> a command of the first group of management command returned an error!\n"); printk("data: %s\n", data); if (attempted_dest_id != NULL) printk("TIPC------> Attempted processor address: %u\n",attempted_dest_id->processor); if (attempted_dest_name != NULL) printk("TIPC------> Attempted portname type: %u portname Instance: %u\n", attempted_dest_name->type, attempted_dest_name->instance); printk("TIPC------> Reason of failure: "); error_msg_code_reason(reason); return dummy; } static tipc_message_event get_bearers_cb(void *userdata, tipc_id_t portid, unsigned char const *data, unsigned int size, tipc_portreference const *origin, tipc_msg_importance importance, void **buf) { static struct tipc_command_result_msg *get_bearers_cb_result; tipc_message_event dummy = (tipc_message_event) 0; get_bearers_cb_result = (tipc_command_result_msg *) data; strcpy(result_bearers_cb, get_bearers_cb_result->result.str); get_bearers_cb_done = 1; wake_up(&queues[BEARERS_TYPE]); return dummy; } static tipc_message_event get_links_cb(void *userdata, tipc_id_t portid, unsigned char const *data, unsigned int size, tipc_portreference const *origin, tipc_msg_importance importance, void **buf) { static struct tipc_command_result_msg *get_links_cb_result; tipc_message_event dummy = (tipc_message_event) 0; get_links_cb_result = (tipc_command_result_msg *) data; nb_links = ntohl(get_links_cb_result->result_len) / sizeof (get_links_cb_result->result.link_event); strcpy(result_links_cb, get_links_cb_result->result.str); //printk("Links in callback: %s\n", result_links_cb); get_links_cb_done = 1; wake_up(&queues[LINKS_TYPE]); return dummy; } static tipc_message_event get_link_stats_cb(void *userdata, tipc_id_t portid, unsigned char const *data, unsigned int size, tipc_portreference const *origin, tipc_msg_importance importance, void **buf) { static struct tipc_command_result_msg *get_link_stats_cb_result; tipc_message_event dummy = (tipc_message_event) 0; get_link_stats_cb_result = (tipc_command_result_msg *) data; strncpy(result_link_stats_cb, get_link_stats_cb_result->result.str, ntohl(get_link_stats_cb_result->result_len)); get_link_stats_cb_done = 1; wake_up(&queues[LINK_STATS_TYPE]); return dummy; } static tipc_message_event get_peer_address_cb(void *userdata, tipc_id_t portid, unsigned char const *data, unsigned int size, tipc_portreference const *origin, tipc_msg_importance importance, void **buf) { static struct tipc_command_result_msg *get_peer_address_cb_result; tipc_message_event dummy = (tipc_message_event) 0; get_peer_address_cb_result = (tipc_command_result_msg *) data; strncpy(result_peer_address_cb, get_peer_address_cb_result->result.peer_address, ntohl(get_peer_address_cb_result->result_len)); get_peer_address_cb_done = 1; wake_up(&queues[PEER_ADDRESS_TYPE]); return dummy; } static tipc_message_event reset_link_stats_cb(void *userdata, tipc_id_t portid, unsigned char const *data, unsigned int size, tipc_portreference const *origin, tipc_msg_importance importance, void **buf) { static struct tipc_command_result_msg *reset_link_stats_cb_result; tipc_message_event dummy = (tipc_message_event) 0; reset_link_stats_cb_result = (tipc_command_result_msg *) data; reset_link_stats_cb_done = 1; wake_up(&queues[RESET_LINK_TYPE]); return dummy; } static tipc_message_event get_name_table_cb(void *userdata, tipc_id_t portid, unsigned char const *data, unsigned int size, tipc_portreference const *origin, tipc_msg_importance importance, void **buf) { static struct tipc_command_result_msg *get_name_table_cb_result; tipc_message_event dummy = (tipc_message_event) 0; get_name_table_cb_result = (tipc_command_result_msg *) data; strncpy(result_name_table_cb, get_name_table_cb_result->result.str, ntohl(get_name_table_cb_result->result_len)); memset(result_name_table_cb + ntohl(get_name_table_cb_result->result_len) - 1, '\0', 1); get_name_table_cb_done = 1; wake_up(&queues[NAME_TABLE_TYPE]); return dummy; } static tipc_message_event get_ports_cb(void *userdata, tipc_id_t portid, unsigned char const *data, unsigned int size, tipc_portreference const *origin, tipc_msg_importance importance, void **buf) { static struct tipc_command_result_msg *get_ports_cb_result; tipc_message_event dummy = (tipc_message_event) 0; get_ports_cb_result = (tipc_command_result_msg *) data; nb_ports = ntohl(get_ports_cb_result->result_len) / sizeof (uint); memcpy(&ports, &get_ports_cb_result->result.ports, ntohl(get_ports_cb_result->result_len)); get_ports_cb_done = 1; wake_up(&queues[PORTS_TYPE]); return dummy; } static tipc_message_event get_port_stats_cb(void *userdata, tipc_id_t portid, unsigned char const *data, unsigned int size, tipc_portreference const *origin, tipc_msg_importance importance, void **buf) { static struct tipc_command_result_msg *get_port_stats_cb_result; tipc_message_event dummy = (tipc_message_event) 0; get_port_stats_cb_result = (tipc_command_result_msg *) data; strncpy(result_port_stats_cb, get_port_stats_cb_result->result.str, ntohl(get_port_stats_cb_result->result_len)); get_port_stats_cb_done = 1; wake_up(&queues[PORT_STATS_TYPE]); return dummy; } static tipc_message_event reset_port_stats_cb(void *userdata, tipc_id_t portid, unsigned char const *data, unsigned int size, tipc_portreference const *origin, tipc_msg_importance importance, void **buf) { static struct tipc_command_result_msg *reset_port_stats_cb_result; tipc_message_event dummy = (tipc_message_event) 0; reset_port_stats_cb_result = (tipc_command_result_msg *) data; reset_port_stats_cb_done = 1; wake_up(&queues[RESET_PORT_STATS_TYPE]); return dummy; } //The name subscription is used to dynamically update the procfs hierarchy //For now it is not used, as we have a problem with this... //In the Callback, we are in a Kernel space interrupt, so we cannot use a userspace function //like create_proc_entry without crashing the system static tipc_name_status_event create_name_subscription_cb(void *userdata, tipc_id_t subscriptionid, tipc_subscription_event event, unsigned int type, unsigned int found_lower, unsigned int found_upper) { tipc_name_status_event dummy = (tipc_name_status_event) 0; if (event == 0x800) { //printk("TIPC------> Name Subs Cb: New Processor published\n"); os_sendSignal_keventd((SignalHandler) add_proc_to_list, (void *) found_lower); } else if (event == 0x1000) { //printk("TIPC------> Name Subs Cb: Processor removed\n"); os_sendSignal_keventd((SignalHandler) remove_proc_from_list, (void *) found_lower); } return dummy; } /*************** These are the 3 callBacks used by the seconds group of commands of tipc_management.h The tipc_message_event callback should not be called, as these commands use connected messages But there was a problem in the tipc code that called this callback instead. This should not happen again, but I'm leaving the callback here for safety: the manager will find the callback and display stuff instead of crashing in the absence of it ****************/ static tipc_message_event second_cmd_group_event_cb(void *userdata, tipc_id_t portid, unsigned char const *data, unsigned int size, tipc_portreference const *origin, tipc_msg_importance importance, void **buf) { struct tipc_command_result_msg *second_cmd_group_cb_result; tipc_message_event dummy = (tipc_message_event) 0; second_cmd_group_cb_result = (tipc_command_result_msg *) data; printk("TIPC------> >>second_cmd_group_event_cb callback,This probably means we got an error\n"); printk("TIPC------> Returned string: %s\n", second_cmd_group_cb_result->result.str); second_cmd_group_cb_done = 1; wake_up(&queues[SECOND_COMMAND_GROUP_TYPE]); return dummy; } static tipc_connected_message_event second_cmd_group_cb(void *userdata, tipc_id_t portid, unsigned char const *data, unsigned int size, void **buf) { struct tipc_command_result_msg *second_cmd_group_cb_result; tipc_connected_message_event dummy = (tipc_connected_message_event) 0; second_cmd_group_cb_result = (tipc_command_result_msg *) data; printk("TIPC------>>>second_cmd_group_cb callback ->"); if (ntohl(second_cmd_group_cb_result->result_len) == 0) printk("Acknowledgement succesful\n"); else printk("Acknowledgement failed\n"); second_cmd_group_cb_done = 1; wake_up(&queues[SECOND_COMMAND_GROUP_TYPE]); return dummy; } static tipc_connected_error_event second_cmd_group_error_cb(void *userdata, tipc_id_t portid, tipc_msg_error_code reason, void **buf) { tipc_connected_error_event dummy = (tipc_connected_error_event) 0; printk("TIPC------>>>second_cmd_group_error_cb!\n"); printk("TIPC------>Attempted address: %u\n", portid); printk("TIPC------>Reason of failure: \n"); error_msg_code_reason(reason); second_cmd_group_cb_done = 1; wake_up(&queues[SECOND_COMMAND_GROUP_TYPE]); return dummy; } /******************************************************************* Functions that call the Manager for various information ********************************************************************/ /* Does the Attach to the manager. If this fails, subsystem is down. All requests to the manager use the same user. */ static int create_user_to_manager(void) { //Asking the manager port.type = 0; port.instance = tipc_ownAddress; if (tipc_attach(&user, NULL, NULL) == 0) { return 0; } else { return -1; } } /* Used by the first command group */ static void create_port_id(tipc_id_t * portId) { if (*portId == 0) tipc_createport(user, &createport, portId); } /* The second command group shares the same port */ static void create_second_cmd_group_port(void) { struct tipc_createport_argv create_port_argv; if (port_id_second_cmd_group == 0) { create_port_argv.importance = 2; create_port_argv.connected_message_cb = (tipc_connected_message_event) second_cmd_group_cb; create_port_argv.connected_error_cb = (tipc_connected_error_event) second_cmd_group_error_cb; create_port_argv.message_cb = (tipc_message_event) second_cmd_group_event_cb; tipc_createport(user, &create_port_argv, &port_id_second_cmd_group); //printk("port_id_second_cmd_group: %u \n",port_id_second_cmd_group); } } /* For the second command group, upon the first Succesful Acknoledgement, the port stays connected, so subsequent calls must use tipc_send instead of tipc_send2name, else we get an error (attempt to write to port in wrong state) */ static void send_depending_on_connect(tipc_portname * port, tipc_message_section * msg) { int connected = -1; tipc_isconnected(port_id_second_cmd_group, &connected); if (connected) { tipc_send(port_id_second_cmd_group, 1, msg); } else { tipc_send2name(port_id_second_cmd_group, port, 0, 1, msg); } } /* When a processor is added or removed from the zone, this callback is fired. We use it to dynamically update the hierarchy of the procfs */ static void create_name_subscription(void) { struct tipc_name_subscription_argv name_argv; tipc_id_t subscriptionId; char address[50] = { 0 }; //Asking the manager port.type = 0; port.instance = tipc_ownAddress; name_argv.userdata = NULL; name_argv.type = 0; //set the range of the subscription depending on the defined variables sprintf(address, "%u.%u.%u", addr_zone(tipc_ownAddress), addr_subnet(tipc_ownAddress), (uint) 0); name_argv.lowerbound = addr_atoi(address); sprintf(address, "%u.%u.%u", addr_zone(tipc_ownAddress), addr_subnet(tipc_ownAddress), (uint) MAX_PROCS_BY_SUBNET - 1); name_argv.upperbound = addr_atoi(address); //no timeout name_argv.timeout = 0xffffffff; name_argv.name_event_cb = (tipc_name_status_event) create_name_subscription_cb; tipc_subscribe2name(user, &name_argv, &subscriptionId); } static void manager_request(int type, tipc_id_t address, const char *str, uint value, const tipc_bearer_addr bear_addr) { //printk("manager1\n"); tipc_id_t *port_id = NULL; struct tipc_command_msg cmd_msg; struct tipc_message_section msg; createport.importance = 2; //printk("manager2\n"); //printk("value: %d str: %s addresss: %u\n", value, str, address); port.type = 0; if (address != 0) port.instance = address; else port.instance = tipc_ownAddress; switch (type) { case (PROCESSORS_TYPE): //printk("manager case get processors\n"); port_id = &port_id_processor; createport.message_cb = (tipc_message_event) get_processors_cb; cmd_msg.command = htonl(TIPC_GET_PROCESSORS); cmd_msg.argv.scope = 0; break; case (BEARERS_TYPE): port_id = &port_id_bearers; createport.message_cb = (tipc_message_event) get_bearers_cb; cmd_msg.command = htonl(TIPC_GET_BEARERS); //cmd_msg.argv.scope = 0; break; case (LINKS_TYPE): port_id = &port_id_links; createport.message_cb = (tipc_message_event) get_links_cb; cmd_msg.command = htonl(TIPC_GET_LINKS); cmd_msg.argv.scope = 0; break; case (LINK_STATS_TYPE): //printk("link stats type manager\n"); port_id = &port_id_link_stats; createport.message_cb = (tipc_message_event) get_link_stats_cb; cmd_msg.command = htonl(TIPC_GET_LINK_STATISTICS); strcpy(cmd_msg.argv.link_name, str); break; case (PEER_ADDRESS_TYPE): port_id = &port_id_peer_address; createport.message_cb =(tipc_message_event) get_peer_address_cb; cmd_msg.command = htonl(TIPC_GET_PEER_ADDRESS); strcpy(cmd_msg.argv.link_name, str); break; case (RESET_LINK_TYPE): port_id = &port_id_reset_link_stats; createport.message_cb = (tipc_message_event) reset_link_stats_cb; cmd_msg.command = htonl(TIPC_RESET_LINK_STATISTICS); strcpy(cmd_msg.argv.link_name, str); break; case (NAME_TABLE_TYPE): port_id = &port_id_name_table; struct tipc_get_name_table_argv name_table_argv; name_table_argv.type = 0; name_table_argv.depth = htonl(value); //only works for 0?? createport.message_cb = (tipc_message_event) get_name_table_cb; cmd_msg.command = htonl(TIPC_GET_NAME_TABLE); //create_port_id(&port_id_name_table); cmd_msg.argv.get_name_table = name_table_argv; //cmd_msg.argv.scope = 0; break; case (PORTS_TYPE): port_id = &port_id_id_ports; createport.message_cb = (tipc_message_event) get_ports_cb; cmd_msg.command = htonl(TIPC_GET_PORTS); break; case (PORT_STATS_TYPE): port_id = &port_id_port_stats; createport.message_cb = (tipc_message_event) get_port_stats_cb; cmd_msg.command = htonl(TIPC_GET_PORT_STATISTICS); memcpy(&cmd_msg.argv.port_ref, &value, sizeof (uint)); break; case (RESET_PORT_STATS_TYPE): port_id = &port_id_reset_stats; createport.message_cb = (tipc_message_event) reset_port_stats_cb; cmd_msg.command = htonl(TIPC_RESET_PORT_STATISTICS); memcpy(&cmd_msg.argv.port_ref, &value, sizeof (uint)); break; case (CREATE_LINK_TYPE): strcpy(cmd_msg.argv.create_link.bearer_name, str); strcpy(cmd_msg.argv.create_link.peer_addr, bear_addr); cmd_msg.command = htonl(TIPC_CREATE_LINK); break; case (REMOVE_LINK_TYPE): strcpy(cmd_msg.argv.link_name, str); cmd_msg.command = htonl(TIPC_REMOVE_LINK); break; case (BLOCK_LINK_TYPE): strcpy(cmd_msg.argv.link_name, str); cmd_msg.command = htonl(TIPC_BLOCK_LINK); break; case (UNBLOCK_LINK_TYPE): strcpy(cmd_msg.argv.link_name, str); cmd_msg.command = htonl(TIPC_UNBLOCK_LINK); break; case (SET_LINK_TOLERANCE_TYPE): cmd_msg.argv.configure_link.value = ntohl(value); cmd_msg.command = htonl(TIPC_SET_LINK_TOLERANCE); strcpy(cmd_msg.argv.configure_link.name, str); break; case (SET_LINK_PRIORITY_TYPE): cmd_msg.argv.configure_link.value = ntohl(value); cmd_msg.command = htonl(TIPC_SET_LINK_PRIORITY); strcpy(cmd_msg.argv.configure_link.name, str); break; case (SET_LINK_WINDOW_TYPE): cmd_msg.argv.configure_link.value = ntohl(value); cmd_msg.command = htonl(TIPC_SET_LINK_WINDOW); strcpy(cmd_msg.argv.configure_link.name, str); break; case (ENABLE_BEARER_TYPE): strcpy(cmd_msg.argv.enable_bearer.name, str); cmd_msg.command = htonl(TIPC_ENABLE_BEARER); cmd_msg.argv.enable_bearer.priority = htonl(value); break; case (DISABLE_BEARER_TYPE): strcpy(cmd_msg.argv.bearer_name, str); cmd_msg.command = htonl(TIPC_DISABLE_BEARER); break; } msg.data = (char *) &cmd_msg; msg.size = sizeof (cmd_msg); if (type <= NAME_TABLE_TYPE) { //printk("before create_port_id\n"); createport.error_cb = (tipc_error_event) first_cmd_group_error_cb; //printk("poc id pointer: %p\n", port_id); create_port_id(port_id); //printk("after create_port_id\n"); tipc_send2name(*port_id, &port, 0, 1, &msg); //printk("after tipc_send2name\n"); } else { create_second_cmd_group_port(); send_depending_on_connect(&port, &msg); } } /***************************************** Functions supporting the proc file system ******************************************/ /* frees the memory that was allocated to hold the name of the processor Links */ static void free_proc_link_names(int procNb) { int i; //for all the possible links on a proc for (i = 0; i < MAX_PROCS_BY_SUBNET * MAX_LINK_BY_PROC; i++) { if (procs[procNb]->links[i] != NULL) { // printk("Index %u is not NULL!\n",i); kfree((char *) procs[procNb]->links[i]); procs[procNb]->links[i] = NULL; } } //resetting the list INIT_LIST_HEAD(&procs[procNb]->list_links); } /* free the Links Directory and the links inside */ static void free_proc_link_dir(int procNb) { struct list_head *pos; struct link_name *tmp; if (procs[procNb]->links_dir != NULL) { //the get_links file was read, so the Links dir exits{ list_for_each(pos, &procs[procNb]->list_links) { tmp = list_entry(pos, struct link_name, next); remove_proc_entry(tmp->name, procs[procNb]->links_dir); } remove_proc_entry("Links", procs[procNb]->this); procs[procNb]->links_dir = NULL; } } static void free_proc_links(int procNb) { free_proc_link_dir(procNb); free_proc_link_names(procNb); } /* frees the memory that was allocated to hold the name of the processor Ports */ static void free_proc_port_names(int procNb) { // printk(">>free_proc_port_names\n"); int i; //for all the possible Ports on a proc for (i = 0; i < MAX_PORTS; i++) { if (procs[procNb]->ports[i] != NULL) { kfree((char *) procs[procNb]->ports[i]); procs[procNb]->ports[i] = NULL; } } //resetting the list INIT_LIST_HEAD(&procs[procNb]->list_ports); } static void free_proc_port_dir(int procNb) { struct list_head *pos; struct generic_proc_entry *tmp; if (procs[procNb]->ports_dir != NULL) { //the get_links file was read, so the Links dir exits{ list_for_each(pos, &procs[procNb]->list_ports) { tmp = list_entry(pos, struct generic_proc_entry, next); remove_proc_entry(tmp->name, procs[procNb]->ports_dir); // printk("removing port Directory: %s\n",tmp->name); } remove_proc_entry("Ports", procs[procNb]->this); procs[procNb]->ports_dir = NULL; } } static void free_proc_ports(int procNb) { free_proc_port_dir(procNb); free_proc_port_names(procNb); } /* Free the memory allocated to hold the bearer_types and Names, and reinitialize the lists */ static void free_bearers_names(int procNb) { int i; //for all the possible bearers for (i = 0; i < MAX_BEARER_TYPES; i++) { if (procs[procNb]->bearer_types[i] != NULL) { // printk("Index %u is not NULL!\n",i); kfree((char *) procs[procNb]->bearer_types[i]); procs[procNb]->bearer_types[i] = NULL; } } //resetting the list INIT_LIST_HEAD(&procs[procNb]->list_bearer_types); for (i = 0; i < MAX_BEARER_NAMES; i++) { if (procs[procNb]->bearer_names[i] != NULL) { kfree((char *) procs[procNb]->bearer_names[i]); procs[procNb]->bearer_names[i] = NULL; } } //resetting the list INIT_LIST_HEAD(&procs[procNb]->list_bearer_names); } /* We remove the bearer_names first, and then the bearer_types, since bearer_names are under Types in the hierarchy */ static void free_bearers_dir(int procNb) { struct list_head *pos; struct proc_entry_with_dir *tmp; if (procs[procNb]->bearers_dir != NULL) { //the get_bearers file was read, so the Bearers dir exits{ list_for_each(pos, &procs[procNb]->list_bearer_names) { tmp = list_entry(pos, struct proc_entry_with_dir, next); remove_proc_entry(tmp->name, tmp->dir); //we stored its parent there } list_for_each(pos, &procs[procNb]->list_bearer_types) { tmp = list_entry(pos, struct proc_entry_with_dir, next); //printk("removing bearerType directory : %s\n",tmp->name); remove_proc_entry(tmp->name,procs[procNb]->bearers_dir); } remove_proc_entry("Bearers", procs[procNb]->this); procs[procNb]->bearers_dir = NULL; } } static void free_proc_bearers(int procNb) { free_bearers_dir(procNb); free_bearers_names(procNb); } /*when opening the "get_links" file, the Links directory is created, with subdirs for each link the names of these links must be kept, so that upon removal of the processor, we can do a remove_proc_entry for each of the subdirectory! this function adds a link name to a processor */ static void addLinkToProc(int procNb, char *str) { int i; //for all possible links for (i = 0; i < MAX_PROCS_BY_SUBNET * MAX_LINK_BY_PROC; i++) { //take the 1st available pointer if (procs[procNb]->links[i] == NULL) { procs[procNb]->links[i] = (struct link_name *) os_malloc(sizeof (struct link_name)); strcpy(procs[procNb]->links[i]->name, str); //add the link to the list of the processor list_add_tail(&procs[procNb]->links[i]->next, &procs[procNb]->list_links); return; } } //dit not return, all pointers are used (should not happen!) } static void add_port_to_proc(int procNb, char *str) { int i; //for all possible ports for (i = 0; i < MAX_PORTS; i++) { //take the 1st available pointer if (procs[procNb]->ports[i] == NULL) { procs[procNb]->ports[i] = (struct generic_proc_entry *) os_malloc(sizeof (struct generic_proc_entry)); strcpy(procs[procNb]->ports[i]->name, str); //add the link to the list of the processor list_add_tail(&procs[procNb]->ports[i]->next, &procs[procNb]->list_ports); return; } } //dit not return, all pointers are used (should not happen!) printk ("TIPC------>ERROR in add_port_to_proc: All the generic_proc_entry structs of the specified processor are full!\n"); } /* Same thing, but for bearers, the function also CREATES the directory */ static void add_bearer_type_to_proc(char *bearerType, int procNb) { struct list_head *pos; struct proc_entry_with_dir *tmp; struct proc_dir_entry *tmpDir; int flag = 0, i; //check to see if the bearerType already exists for the processor list_for_each(pos, &procs[procNb]->list_bearer_types) { tmp = list_entry(pos, struct proc_entry_with_dir, next); if (strcmp(tmp->name, bearerType) == 0) { flag = 1; //bearerType already exists for the processor break; //get out of the list_for_each } } if (!flag) { // bearerType wasn't in the processors's list, so we must add it and create the proc_entry //add the bearerType to the processor for (i = 0; i < MAX_BEARER_TYPES; i++) { //take the 1st available pointer if (procs[procNb]->bearer_types[i] == NULL) { tmpDir = proc_mkdir(bearerType, procs[procNb]->bearers_dir); procs[procNb]->bearer_types[i] = (struct proc_entry_with_dir *) os_malloc(sizeof (struct proc_entry_with_dir)); strcpy(procs[procNb]->bearer_types[i]->name, bearerType); //the bearer_types keeps its own proc_dir_entry procs[procNb]->bearer_types[i]->dir = tmpDir; //add the bearerType to the list of the processor list_add_tail(&procs[procNb]->bearer_types[i]-> next, &procs[procNb]-> list_bearer_types); return; } } //dit not return, all pointers are used (should not happen!) printk ("TIPC------>Error in add_bearer_type_to_proc: All the proc_entry_with_dir structs of the specified processor are full!\n"); } } static struct proc_dir_entry * add_bearer_name_to_proc(char *bearerType, char *bearerName, int procNb) { struct list_head *pos; struct proc_entry_with_dir *bearerTypeDir = NULL; struct proc_dir_entry *tmpDir = (struct proc_dir_entry *) 0; int flag = 0, i; //here, we are finding the proc_entry_with_dir of the bearerType list_for_each(pos, &procs[procNb]->list_bearer_types) { bearerTypeDir =list_entry(pos, struct proc_entry_with_dir, next); if (strcmp(bearerTypeDir->name, bearerType) == 0) { flag = 1; //bearerType already exists for the processor break; //get out of the list_for_each } } if (flag) { //the bearerType should always be in the list, since it was added before the bearerName for (i = 0; i < MAX_BEARER_NAMES; i++) { //take the 1st available pointer if (procs[procNb]->bearer_names[i] == NULL) { //create the directory, the parent is the bearerType already found tmpDir = proc_mkdir(bearerName, bearerTypeDir->dir); procs[procNb]->bearer_names[i] = (struct proc_entry_with_dir *) os_malloc(sizeof (struct proc_entry_with_dir)); strcpy(procs[procNb]->bearer_names[i]->name, bearerName); //the bearerName keeps a pointer to its parent procs[procNb]->bearer_names[i]->dir = bearerTypeDir->dir; //add the bearerName to the list of the processor list_add_tail(&procs[procNb]->bearer_names[i]->next,&procs[procNb]-> list_bearer_names); return tmpDir; } } //dit not return, all pointers are used (should not happen!) printk("TIPC------>Error in add_bearer_name_to_proc All the proc_entry_with_dir structs of the specified processor are full!\n"); return tmpDir; } else { printk ("TIPC------> BearerType: %s not found in the processors list for bearerName: %s !\n", bearerType, bearerName); return tmpDir; } } /* Called by parse_string_and_action Uses the result of a callBack, and calls the functions to create the directories/files from that data */ static void __parse_string_and_action(struct proc_dir_entry *dir, int procNb, int action) { //printk("__parse_string_and_action\n"); int i; struct proc_dir_entry *tmp, *tmp2; char link[LINK_NAME_LENGTH] = { 0, }; char bearer[20] = { 0, }; char port[20] = { 0, }; char *pos, *beforeString, *bearerType, *bearerName; switch (action) { case LINKS_CREATION:{ //printk("result_links_cb: %s\n", result_links_cb); pos = result_links_cb; do { beforeString = pos; pos = strchr(pos, '\n'); if (pos != NULL) { pos++; //AFTER the \n //we are already in the "Links" directory //memcpy(&link,beforeString+1,pos-beforeString-3); //strip the surrounding < and > of the link, makes for //a better directory name memcpy(&link, beforeString, pos - beforeString - 1); //don't strip here remove_proc_entry(link, dir); tmp = proc_mkdir(link, dir); //add the link the the processor's list addLinkToProc(procNb, link); remove_proc_entry("stats", tmp); tmp2 = create_proc_entry("stats", 0644, tmp); set_proc_attributes(tmp2, LINK_STATS_TYPE); remove_proc_entry("resetStats", tmp); tmp2 = create_proc_entry("resetStats", 0644, tmp); set_proc_attributes(tmp2, RESET_LINK_TYPE); remove_proc_entry("peerAddress", tmp); tmp2 =create_proc_entry("peerAddress", 0644, tmp); set_proc_attributes(tmp2, PEER_ADDRESS_TYPE); remove_proc_entry("remove_link", tmp); tmp2 = create_proc_entry("remove_link", 0644, tmp); set_proc_attributes(tmp2, REMOVE_LINK_TYPE); remove_proc_entry("block_link", tmp); tmp2 =create_proc_entry("block_link", 0644, tmp); set_proc_attributes(tmp2, BLOCK_LINK_TYPE); remove_proc_entry("unblock_link", tmp); tmp2 =create_proc_entry("unblock_link",0644, tmp); set_proc_attributes(tmp2, UNBLOCK_LINK_TYPE); remove_proc_entry ("W_set_link_tolerance", tmp); tmp2 = create_proc_entry ("W_set_link_tolerance", 0644, tmp); set_proc_attributes(tmp2, SET_LINK_TOLERANCE_TYPE); tmp2->write_proc = proc_write_data; remove_proc_entry("W_set_link_priority", tmp); tmp2 = create_proc_entry ("W_set_link_priority", 0644, tmp); set_proc_attributes(tmp2, SET_LINK_PRIORITY_TYPE); tmp2->write_proc = proc_write_data; remove_proc_entry("W_set_link_window",tmp); tmp2 =create_proc_entry ("W_set_link_window", 0644, tmp); set_proc_attributes(tmp2, SET_LINK_WINDOW_TYPE); tmp2->write_proc = proc_write_data; } else { return; } } while ((pos != NULL) && (pos[0] != '\0')); break; } case PORTS_CREATION:{ for (i = 0; i < nb_ports; i++) { strcpy(&port[0], itoa(ports[i])); remove_proc_entry(port, dir); tmp = proc_mkdir(port, dir); add_port_to_proc(procNb, port); remove_proc_entry("stats", tmp); tmp2 = create_proc_entry("stats", 0644, tmp); set_proc_attributes(tmp2, PORT_STATS_TYPE); remove_proc_entry("resetStats", tmp); tmp2 = create_proc_entry("resetStats", 0644, tmp); set_proc_attributes(tmp2, RESET_PORT_STATS_TYPE); } return; break; } case BEARERS_CREATION:{ pos = result_bearers_cb; do { beforeString = pos; pos = strchr(pos, '\n'); if (pos != NULL) { pos++; memcpy(&bearer, beforeString, pos - beforeString - 1); //strip the first < bearerType = parse_bearer_type(bearer); bearerName = parse_bearer_name(bearer); add_bearer_type_to_proc(bearerType, procNb); //bearerName is under a bearerType tmp = add_bearer_name_to_proc(bearerType, bearerName, procNb); kfree((char *) bearerType); kfree((char *) bearerName); remove_proc_entry("disable_bearer", tmp); tmp2 =create_proc_entry("disable_bearer", 0644, tmp); set_proc_attributes(tmp2, DISABLE_BEARER_TYPE); } else { return; } } while ((pos != NULL) && (pos[0] != '\0')); break; } default:{ return; break; } } } /* Takes a processorsNb and an action to accomplish */ static void parse_string_and_action(int proc_nb, int action) { struct proc_dir_entry *dir; dir = procs[proc_nb]->this; //main action of the function switch (action) { case LINKS_CREATION:{ dir = proc_mkdir("Links", dir); procs[proc_nb]->links_dir = dir; __parse_string_and_action(dir, proc_nb, action); //creates the indiviual Links directories break; } case PORTS_CREATION:{ dir = proc_mkdir("Ports", dir); procs[proc_nb]->ports_dir = dir; //str will be NULL __parse_string_and_action(dir, proc_nb, action); break; } case BEARERS_CREATION:{ dir = proc_mkdir("Bearers", dir); procs[proc_nb]->bearers_dir = dir; __parse_string_and_action(dir, proc_nb, action); //creates the indiviual Links directories break; } } } /*********************************************** Functions that engage callBack functions, and manage the wait for the return Callbacks are put in a global array of waitQueues, 1 for each type ***********************************************/ /* Waits for a Callback for a number of ticks */ static int wait_for_callback(int *callback, int type) { int ret = !wait_event_interruptible_timeout(queues[type], *callback, 500); if (ret == -ERESTARTSYS) { return -ERESTARTSYS; //important, to resume handling of the signals } else if (ret) { printk ("TIPC------> timeout in wait_event_interruptible while asking to manager\n"); return -1; } else { return 0; } } /* Asks to the manager a request for information, waits for the return arg1 is for depth of nametable, and a few others arg2 is for a tipcAddress arg3 is a the name of a link for example, arg4 too Some functions share the same wait_queue and callBacks */ static int ask_manager_and_wait(int type, char *name, int *cb_flag, uint arg1, uint arg2, const char *arg3, char *arg4) { int ret; if (type <= NAME_TABLE_TYPE) { init_waitqueue_head(&queues[type]); } else init_waitqueue_head(&queues[SECOND_COMMAND_GROUP_TYPE]); manager_request(type, arg2, arg3, arg1, arg4); //printk("manager request done\n"); ret = wait_for_callback(cb_flag, type); //printk("wait for callback done\n"); *cb_flag = 0; return ret; } /************************************************** Functions that manage the processors **************************************************/ /* allocates memory for a processor entry in the procs[array] creates the processors's directory in the procfs, possibly adding a new Zone and Subnet */ static void add_proc_to_list(tipc_id_t addr, int available) { struct proc_dir_entry *zoneTmpDir, *subnetTmpDir, *procTmpDir, *fileTmp; int zone, proc, i; char name[LINK_NAME_LENGTH]; zone = addr_zone(addr) - 1; proc = addr_proc(addr) - 1; int procNb = (zone * MAX_PROCS_BY_SUBNET) + proc; //proc already exists (should not happen, it's a security for integrity) if ((zones[zone] == 1) && (subnets[zone] != NULL) && (procs[procNb] != NULL)) { return; } if (zones[zone] == 0) { sprintf(name, "%d", zone + 1); //printk("name: %s\n",name); // printk("network_dir pointer: %p\n",network_dir); zoneTmpDir = proc_mkdir(name, network_dir); zones[zone] = 1; sprintf(name, "%d", zone + 1); // printk("zoneTmpDir pointer: %p\n",zoneTmpDir); subnetTmpDir = proc_mkdir(name, zoneTmpDir); subnets[zone] = (struct subnet_dir_entry *) os_malloc(sizeof (struct subnet_dir_entry)); subnets[zone]->parent = zoneTmpDir; subnets[zone]->this = subnetTmpDir; } if (procs[procNb] == NULL) { // printk("Creating Proc %u\n",proc+1); sprintf(name, "%d", proc + 1); //printk("name: %s\n",name); procs[procNb] = (struct my_proc_dir_entry *) os_malloc(sizeof (struct my_proc_dir_entry)); procTmpDir = proc_mkdir(name, subnets[zone]->this); procs[procNb]->parent = subnets[zone]->this; procs[procNb]->this = procTmpDir; INIT_LIST_HEAD(&procs[procNb]->list_links); INIT_LIST_HEAD(&procs[procNb]->list_ports); INIT_LIST_HEAD(&procs[procNb]->list_bearer_types); INIT_LIST_HEAD(&procs[procNb]->list_bearer_names); //Not necessary??? for (i = 0; i < MAX_PROCS_BY_SUBNET * MAX_LINK_BY_PROC; i++) { procs[procNb]->links[i] = NULL; } for (i = 0; i < MAX_PORTS; i++) { procs[procNb]->ports[i] = NULL; } for (i = 0; i < MAX_BEARER_TYPES; i++) { procs[procNb]->bearer_types[i] = NULL; } for (i = 0; i < MAX_BEARER_NAMES; i++) { procs[procNb]->bearer_names[i] = NULL; } if (available) { fileTmp = create_proc_entry("get_links", 0644, procTmpDir); set_proc_attributes(fileTmp, LINKS_TYPE); fileTmp = create_proc_entry("get_ports", 0644, procTmpDir); set_proc_attributes(fileTmp, PORTS_TYPE); fileTmp = create_proc_entry("get_bearers", 0644, procTmpDir); set_proc_attributes(fileTmp, BEARERS_TYPE); fileTmp = create_proc_entry("nametable_0", 0644, procTmpDir); set_proc_attributes(fileTmp, NAME_TABLE_TYPE); //fileTmp->proc_fops = &get_name_table_fops; fileTmp = create_proc_entry("nametable_1", 0644, procTmpDir); set_proc_attributes(fileTmp, NAME_TABLE_TYPE); fileTmp = create_proc_entry("nametable_2", 0644, procTmpDir); set_proc_attributes(fileTmp, NAME_TABLE_TYPE); fileTmp = create_proc_entry("W_create_link", 0644, procTmpDir); fileTmp->write_proc = proc_write_data; set_proc_attributes(fileTmp, CREATE_LINK_TYPE); fileTmp = create_proc_entry("W_enable_bearer", 0644, procTmpDir); fileTmp->write_proc = proc_write_data; set_proc_attributes(fileTmp, ENABLE_BEARER_TYPE); } else { fileTmp = create_proc_entry("Processor_Not_Available", 0644, procTmpDir); set_proc_attributes(fileTmp, PROC_NA_TYPE); } } } /* frees the memory allocated for the proc_dir_entry struct, and the underlying list of Links, ports etc deletes the directories to keep the integrity of the procfs */ static void remove_proc_from_list(tipc_id_t addr) { char name[LINK_NAME_LENGTH]; int zone, proc, i, flag = 1; zone = addr_zone(addr) - 1; proc = addr_proc(addr) - 1; int procNb = (zone * MAX_PROCS_BY_SUBNET) + proc; //remove the specified processor if (procs[procNb] != NULL) { //free the LinkNames array of the processors and the Links Directory free_proc_links(procNb); free_proc_ports(procNb); free_proc_bearers(procNb); sprintf(name, "%d", proc + 1); //remove the files and the processor dir itself if (procs[procNb]->available) { remove_proc_entry("get_links", procs[procNb]->this); remove_proc_entry("get_ports", procs[procNb]->this); remove_proc_entry("get_bearers", procs[procNb]->this); remove_proc_entry("nametable_0", procs[procNb]->this); remove_proc_entry("nametable_1", procs[procNb]->this); remove_proc_entry("nametable_2", procs[procNb]->this); remove_proc_entry("W_create_link", procs[procNb]->this); remove_proc_entry("W_enable_bearer", procs[procNb]->this); } else { remove_proc_entry("Processor_Not_Available", procs[procNb]->this); } remove_proc_entry(name, procs[procNb]->parent); kfree((char *) procs[procNb]); procs[procNb] = NULL; } //if all the processors of the zone are gone, we must remove the zone too for (i = (zone * MAX_PROCS_BY_SUBNET); i < (zone + 1) * MAX_PROCS_BY_SUBNET; i++) { //we have at least 1 processor active in the zone if (procs[i] != NULL) { flag = 0; break; } } //all processors are gone, remove subnet and zone if (flag) { //printk("All processors of subnet gone, removing Subnet and Zone %u\n",zone+1); sprintf(name, "%d", zone + 1); remove_proc_entry(name, network_dir); zones[zone] = 0; sprintf(name, "%d", zone + 1); remove_proc_entry(name, subnets[zone]->parent); kfree((char *) subnets[zone]); subnets[zone] = NULL; } } /* Well duh! ;) */ static void remove_all_processors(void) { int i; uint zone, proc, proc_addr; for (i = 0; i < MAX_PROCS_ON_NETWORK; i++) { if (procs[i] != NULL) { //processor exists //we recreate a tipc address from the iterator zone = i / MAX_PROCS_BY_SUBNET + 1; proc = i % MAX_PROCS_BY_SUBNET + 1; proc_addr = (zone << 24) + (zone << 12) + proc; //right now, zone == subnet remove_proc_from_list(proc_addr); } } } /* Called when opening the scan_network file of the procfs for example Asks for the current list of processors, updates the procfs hierarchy accordingly */ static void get_network_info_from_procs(void) { int i, ret, proc_nb; tipc_id_t proc_addr; //we assume that all the processors don't exist anymore for (i = 0; i < MAX_PROCS_BY_SUBNET * MAX_LINK_BY_PROC; i++) { if (procs[i] != NULL) procs[i]->exists = 0; } //get_processorsAndWait(); ret =ask_manager_and_wait(PROCESSORS_TYPE, "get_processors", &get_processors_cb_done, 0, 0, NULL, NULL); if (ret == -1) printk("TIPC------>get_processors request failed..\n"); else { //for all the current existing processors for (i = 0; i < nb_procs; i++) { proc_addr = ntohl(get_processors_cb_result->result.processors[i].addr); proc_nb = addr_to_proc_nb(proc_addr); if (proc_addr == 1) { //printk("processor available\n"); //if the processors isn't in the procfs, we add it if (procs[proc_nb] == NULL) { // printk("Address of processor added to list: %u\n", ntohl(get_processors_cb_result->result.processors[i].addr)); add_proc_to_list(proc_addr, 1); } else { //processor already exists //processor is changing state, we add it again if (procs[proc_nb]->available == 0) { //printk("processor used to be NA, but now it is back\n"); remove_proc_from_list (proc_nb_to_addr(i)); add_proc_to_list(proc_addr, 1); } } //wether it was in the procfs or not, we must now say it exists procs[proc_nb]->exists = 1; procs[proc_nb]->available = 1; } else { //we list the processors even if they are not available, but they won't have the common entries, //only a Procerrors_not_available entry //processor used to be available, now it isn't //processors doesn't exist in the list if (procs[proc_nb] == NULL) { add_proc_to_list(proc_addr, 0); } else { //processor exists //but changing state! if (procs[proc_nb]->available == 1) { remove_proc_from_list (proc_nb_to_addr(i)); add_proc_to_list(proc_addr, 0); } } //wether it was in the procfs or not, we must now say it exists procs[proc_nb]->exists = 1; procs[proc_nb]->available = 0; } } //now, for the processors who existed in a previous scan ... [truncated message content] |