1 /* 2 * This file contains the table with socket driver mappings. One socket driver 3 * may implement multiple domains (e.g., PF_INET and PF_INET6). For this 4 * reason, we assign a unique number to each socket driver, and use a "socket 5 * device map" table (smap) that maps from those numbers to information about 6 * socket drivers. This number is combined with a per-driver socket identifier 7 * to form a globally unique socket ID (64-bit, stored as dev_t). In addition, 8 * we use a table that maps from PF_xxx domains to socket drivers (pfmap). 9 */ 10 11 #include "fs.h" 12 #include <sys/socket.h> 13 #include <assert.h> 14 15 static struct smap smap[NR_SOCKDEVS]; 16 static struct smap *pfmap[PF_MAX]; 17 18 /* 19 * Initialize the socket device map table. 20 */ 21 void 22 init_smap(void) 23 { 24 unsigned int i; 25 26 for (i = 0; i < __arraycount(smap); i++) { 27 /* 28 * The smap numbers are one-based so as to ensure that no 29 * socket will have the device number NO_DEV, which would 30 * create problems with eg the select code. 31 */ 32 smap[i].smap_num = i + 1; 33 smap[i].smap_endpt = NONE; 34 } 35 36 memset(pfmap, 0, sizeof(pfmap)); 37 } 38 39 /* 40 * Register a socket driver. This action can only be requested by RS. The 41 * process identified by the given DS label 'label' and endpoint 'endpt' is to 42 * be responsible for sockets created in the domains as given in the 'domains' 43 * array, which contains 'ndomains' elements. Return OK upon successful 44 * registration, or an error code otherwise. 45 */ 46 int 47 smap_map(const char * label, endpoint_t endpt, const int * domains, 48 unsigned int ndomains) 49 { 50 struct smap *sp; 51 unsigned int i, num = 0; 52 int domain; 53 54 if (ndomains <= 0 || ndomains > NR_DOMAIN) 55 return EINVAL; 56 57 /* 58 * See if there is already a socket device map entry for this label. 59 * If so, the socket driver is probably being restarted, and we should 60 * overwrite its previous entry. 61 */ 62 sp = NULL; 63 for (i = 0; i < __arraycount(smap); i++) { 64 if (smap[i].smap_endpt != NONE && 65 !strcmp(smap[i].smap_label, label)) { 66 sp = &smap[i]; 67 break; 68 } 69 } 70 71 /* 72 * See if all given domains are valid and not already reserved by a 73 * socket driver other than (if applicable) this driver's old instance. 74 */ 75 for (i = 0; i < ndomains; i++) { 76 domain = domains[i]; 77 if (domain < 0 || domain >= __arraycount(pfmap)) 78 return EINVAL; 79 if (domain == PF_UNSPEC) 80 return EINVAL; 81 if (pfmap[domain] != NULL && pfmap[domain] != sp) 82 return EBUSY; 83 } 84 85 /* 86 * If we are not about to replace an existing socket device map entry, 87 * find a free entry, returning an error if all entries are in use. 88 */ 89 if (sp == NULL) { 90 for (num = 0; num < __arraycount(smap); num++) 91 if (smap[num].smap_endpt == NONE) 92 break; 93 94 if (num == __arraycount(smap)) 95 return ENOMEM; 96 } else 97 num = (unsigned int)(sp - smap); 98 99 /* 100 * At this point, the registration will succeed, and we can start 101 * modifying tables. Just to be sure, unmap the domain mappings for 102 * the old instance, in case it is somehow registered with a different 103 * set of domains. Also, if the endpoint of the service has changed, 104 * cancel any operations involving the previous endpoint and invalidate 105 * any preexisting sockets. However, for stateful restarts where the 106 * service endpoint does not change, leave things as is. 107 */ 108 if (sp != NULL) { 109 if (sp->smap_endpt != endpt) { 110 /* 111 * For stateless restarts, it is common that the new 112 * endpoint is made ready before the old endpoint is 113 * exited, so we cannot wait for the exit handling code 114 * to do these steps, as they rely on the old socket 115 * mapping still being around. 116 */ 117 unsuspend_by_endpt(sp->smap_endpt); 118 119 invalidate_filp_by_sock_drv(sp->smap_num); 120 } 121 122 for (i = 0; i < __arraycount(pfmap); i++) 123 if (pfmap[i] == sp) 124 pfmap[i] = NULL; 125 } 126 127 /* 128 * Initialize the socket driver map entry, and set up the domain map 129 * entries. 130 */ 131 sp = &smap[num]; 132 sp->smap_endpt = endpt; 133 strlcpy(sp->smap_label, label, sizeof(sp->smap_label)); 134 sp->smap_sel_busy = FALSE; 135 sp->smap_sel_filp = NULL; 136 137 for (i = 0; i < ndomains; i++) 138 pfmap[domains[i]] = sp; 139 140 return OK; 141 } 142 143 /* 144 * The process with the given endpoint has exited. If the endpoint identifies 145 * a socket driver, deregister the driver and invalidate any sockets it owned. 146 */ 147 void 148 smap_unmap_by_endpt(endpoint_t endpt) 149 { 150 struct smap *sp; 151 unsigned int i; 152 153 if ((sp = get_smap_by_endpt(endpt)) == NULL) 154 return; 155 156 /* 157 * Invalidation requires that the smap entry still be around, so do 158 * this before clearing the endpoint. 159 */ 160 invalidate_filp_by_sock_drv(sp->smap_num); 161 162 sp->smap_endpt = NONE; 163 164 for (i = 0; i < __arraycount(pfmap); i++) 165 if (pfmap[i] == sp) 166 pfmap[i] = NULL; 167 } 168 169 /* 170 * The given endpoint has announced itself as a socket driver. 171 */ 172 void 173 smap_endpt_up(endpoint_t endpt) 174 { 175 struct smap *sp; 176 177 if ((sp = get_smap_by_endpt(endpt)) == NULL) 178 return; 179 180 /* 181 * The announcement indicates that the socket driver has either started 182 * anew or restarted statelessly. In the second case, none of its 183 * previously existing sockets will have survived, so mark them as 184 * invalid. 185 */ 186 invalidate_filp_by_sock_drv(sp->smap_num); 187 } 188 189 /* 190 * Construct a device number that combines the entry number of the given socket 191 * map and the given per-driver socket identifier, thus constructing a unique 192 * identifier for the socket. Generally speaking, we use the dev_t type 193 * because the value is stored as special device number (sdev) on a socket node 194 * on PFS. We use our own bit division rather than the standard major/minor 195 * division because this simplifies using each half as a 32-bit value. The 196 * block/character device numbers and socket device numbers are in different 197 * namespaces, and numbers may overlap (even though this is currently 198 * practically impossible), so one must always test the file type first. 199 */ 200 dev_t 201 make_smap_dev(struct smap * sp, sockid_t sockid) 202 { 203 204 assert(sp->smap_endpt != NONE); 205 assert(sockid >= 0); 206 207 return (dev_t)(((uint64_t)sp->smap_num << 32) | (uint32_t)sockid); 208 } 209 210 /* 211 * Return a pointer to the smap structure for the socket driver associated with 212 * the socket device number. In addition, if the given socket ID pointer is 213 * not NULL, store the per-driver socket identifier in it. Return NULL if the 214 * given socket device number is not a socket for a valid socket driver. 215 */ 216 struct smap * 217 get_smap_by_dev(dev_t dev, sockid_t * sockidp) 218 { 219 struct smap *sp; 220 unsigned int num; 221 sockid_t id; 222 223 num = (unsigned int)(dev >> 32); 224 id = (sockid_t)(dev & ((1ULL << 32) - 1)); 225 if (num == 0 || num > __arraycount(smap) || id < 0) 226 return NULL; 227 228 sp = &smap[num - 1]; 229 assert(sp->smap_num == num); 230 231 if (sp->smap_endpt == NONE) 232 return NULL; 233 234 if (sockidp != NULL) 235 *sockidp = id; 236 return sp; 237 } 238 239 /* 240 * Return a pointer to the smap structure for the socket driver with the given 241 * endpoint. Return NULL if the endpoint does not identify a socket driver. 242 */ 243 struct smap * 244 get_smap_by_endpt(endpoint_t endpt) 245 { 246 unsigned int i; 247 248 /* 249 * TODO: this function is used rather frequently, so it would be nice 250 * to get rid of the O(n) loop here. The get_dmap_by_endpt() function 251 * suffers from the same problem. It might be worth adding an extra 252 * field to the fproc structure for this. 253 */ 254 for (i = 0; i < __arraycount(smap); i++) 255 if (smap[i].smap_endpt == endpt) 256 return &smap[i]; 257 258 return NULL; 259 } 260 261 /* 262 * Return a pointer to the smap structure for the socket driver handling the 263 * given domain (protocol family). Return NULL if there is no match. 264 */ 265 struct smap * 266 get_smap_by_domain(int domain) 267 { 268 269 if (domain < 0 || domain >= __arraycount(pfmap)) 270 return NULL; 271 272 return pfmap[domain]; /* may be NULL */ 273 } 274