Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/inet/kssl/ksslfilter.c
+++ new/usr/src/uts/common/inet/kssl/ksslfilter.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24
25 25 #include <sys/systm.h>
26 26 #include <sys/cmn_err.h>
27 27 #include <sys/stropts.h>
28 28 #include <sys/strsun.h>
29 29 #include <sys/socketvar.h>
30 30 #include <sys/sockfilter.h>
31 31 #include <inet/kssl/ksslapi.h>
32 32 #include <sys/note.h>
33 33 #include <sys/taskq.h>
34 34
35 35 /*
36 36 * Name of the KSSL filter
↓ open down ↓ |
36 lines elided |
↑ open up ↑ |
37 37 */
38 38 #define KSSL_FILNAME "ksslf"
39 39
40 40 static struct modlmisc ksslf_modlmisc = {
41 41 &mod_miscops,
42 42 "Kernel SSL socket filter"
43 43 };
44 44
45 45 static struct modlinkage ksslf_modlinkage = {
46 46 MODREV_1,
47 - &ksslf_modlmisc,
48 - NULL
47 + { &ksslf_modlmisc, NULL }
49 48 };
50 49
51 50 /*
52 51 * kssl filter cookie
53 52 */
54 53 typedef struct ksslf {
55 54 boolean_t ksslf_pending; /* waiting for 1st SSL rec. */
56 55 boolean_t ksslf_inhandshake; /* during SSL handshake */
57 56 kssl_ent_t ksslf_ent; /* SSL table entry */
58 57 kssl_ctx_t ksslf_ctx; /* SSL session */
59 58 kssl_endpt_type_t ksslf_type; /* is proxy/is proxied/none */
60 59 struct sockaddr_in6 ksslf_laddr; /* local address */
61 60 socklen_t ksslf_laddrlen;
62 61 struct ksslf *ksslf_listener;
63 62 } ksslf_t;
64 63
65 64 static void kssl_input_callback(void *, mblk_t *, kssl_cmd_t);
66 65
67 66 /*
68 67 * Allocate kssl state
69 68 */
70 69 sof_rval_t
71 70 kssl_attach_passive_cb(sof_handle_t handle, sof_handle_t ph,
72 71 void *parg, struct sockaddr *laddr, socklen_t laddrlen,
73 72 struct sockaddr *faddr, socklen_t faddrlen, void **cookiep)
74 73 {
75 74 ksslf_t *listener = (ksslf_t *)parg;
76 75 ksslf_t *new;
77 76
78 77 _NOTE(ARGUNUSED(handle, ph, faddrlen, laddr, laddrlen));
79 78
80 79 if (listener == NULL || listener->ksslf_ent == NULL)
81 80 return (SOF_RVAL_DETACH);
82 81 /*
83 82 * Only way for a fallback listener to receive connections is when
84 83 * a handshake fails and socket is moved from the proxy to the fallback.
85 84 * Connections that come in directly on the fallback are denied.
86 85 */
87 86 if (listener->ksslf_type == KSSL_HAS_PROXY)
88 87 return (SOF_RVAL_EACCES);
89 88
90 89 /* Allocate the SSL context for the new connection */
91 90 new = kmem_zalloc(sizeof (ksslf_t), KM_NOSLEEP);
92 91 if (new == NULL)
93 92 return (SOF_RVAL_ENOMEM);
94 93
95 94 /*
96 95 * The mss is initialized to SSL3_MAX_RECORD_LEN, but might be
97 96 * updated by the mblk_prop callback.
98 97 */
99 98 if (kssl_init_context(listener->ksslf_ent, faddr, SSL3_MAX_RECORD_LEN,
100 99 &new->ksslf_ctx) != KSSL_STS_OK)
101 100 return (SOF_RVAL_ENOMEM);
102 101
103 102 new->ksslf_pending = B_TRUE;
104 103 new->ksslf_inhandshake = B_TRUE;
105 104 ASSERT(laddrlen <= sizeof (new->ksslf_laddr));
106 105 new->ksslf_laddrlen = laddrlen;
107 106 bcopy(laddr, &new->ksslf_laddr, laddrlen);
108 107 new->ksslf_laddr.sin6_port = listener->ksslf_laddr.sin6_port;
109 108 new->ksslf_listener = listener;
110 109
111 110 *cookiep = new;
112 111 /*
113 112 * We are in handshake, defer the notification of this connection
114 113 * until it is completed.
115 114 */
116 115 return (SOF_RVAL_DEFER);
117 116 }
118 117
119 118 void
120 119 kssl_detach_cb(sof_handle_t handle, void *cookie, cred_t *cr)
121 120 {
122 121 ksslf_t *kssl = (ksslf_t *)cookie;
123 122
124 123 _NOTE(ARGUNUSED(handle, cr));
125 124
126 125 if (kssl == NULL)
127 126 return;
128 127
129 128 if (kssl->ksslf_ent != NULL) {
130 129 kssl_release_ent(kssl->ksslf_ent, handle, kssl->ksslf_type);
131 130 kssl->ksslf_ent = NULL;
132 131 }
133 132 if (kssl->ksslf_ctx != NULL) {
134 133 kssl_release_ctx(kssl->ksslf_ctx);
135 134 kssl->ksslf_ctx = NULL;
136 135 }
137 136
138 137 kmem_free(kssl, sizeof (ksslf_t));
139 138 }
140 139
141 140 sof_rval_t
142 141 kssl_bind_cb(sof_handle_t handle, void *cookie, struct sockaddr *name,
143 142 socklen_t *namelen, cred_t *cr)
144 143 {
145 144 kssl_ent_t ent;
146 145 kssl_endpt_type_t type;
147 146 ksslf_t *kssl;
148 147 in_port_t origport;
149 148
150 149 _NOTE(ARGUNUSED(cr));
151 150
152 151 if (cookie != NULL)
153 152 return (SOF_RVAL_EINVAL);
154 153
155 154 if (*namelen < sizeof (struct sockaddr_in)) {
156 155 sof_bypass(handle);
157 156 return (SOF_RVAL_CONTINUE);
158 157 }
159 158
160 159 origport = ((struct sockaddr_in *)name)->sin_port;
161 160 /* Check if KSSL has been configured for this address */
162 161 type = kssl_check_proxy(name, *namelen, handle, &ent);
163 162
164 163 switch (type) {
165 164 case KSSL_NO_PROXY:
166 165 sof_bypass(handle);
167 166 break;
168 167 case KSSL_HAS_PROXY:
169 168 case KSSL_IS_PROXY:
170 169 kssl = kmem_zalloc(sizeof (ksslf_t), KM_SLEEP);
171 170 kssl->ksslf_type = type;
172 171 kssl->ksslf_ent = ent;
173 172
174 173 /*
175 174 * In the unlikely event that there are multiple simultaneous
176 175 * bind requests, and the cookie was already swapped out, then
177 176 * just drop this cookie and let the bind continue unmodified.
178 177 */
179 178 if (sof_cas_cookie(handle, cookie, kssl) != cookie) {
180 179 kssl_release_ent(ent, handle, type);
181 180 kmem_free(kssl, sizeof (ksslf_t));
182 181 ((struct sockaddr_in *)name)->sin_port = origport;
183 182 break;
184 183 }
185 184
186 185 kssl->ksslf_laddrlen = *namelen;
187 186 bcopy(name, &kssl->ksslf_laddr, kssl->ksslf_laddrlen);
188 187 kssl->ksslf_laddr.sin6_port = origport;
189 188 /*
190 189 * kssl_check_proxy updated the sockaddr, so just
191 190 * pass it along to the protocol.
192 191 */
193 192 return ((type == KSSL_HAS_PROXY) ? SOF_RVAL_RETURN :
194 193 SOF_RVAL_CONTINUE);
195 194 }
196 195 return (SOF_RVAL_CONTINUE);
197 196 }
198 197
199 198 sof_rval_t
200 199 kssl_listen_cb(sof_handle_t handle, void *cookie, int *backlog, cred_t *cr)
201 200 {
202 201 ksslf_t *kssl = (ksslf_t *)cookie;
203 202
204 203 _NOTE(ARGUNUSED(backlog, cr));
205 204
206 205 /*
207 206 * The cookie can be NULL in the unlikely event of an application doing
208 207 * listen() without binding to an address. Those listeners are of no
209 208 * interest.
210 209 */
211 210 if (kssl == NULL) {
212 211 sof_bypass(handle);
213 212 return (SOF_RVAL_CONTINUE);
214 213 }
215 214
216 215 return (SOF_RVAL_CONTINUE);
217 216
218 217 }
219 218
220 219 /*
221 220 * Outgoing connections are not of interest, so just bypass the filter.
222 221 */
223 222 sof_rval_t
224 223 kssl_connect_cb(sof_handle_t handle, void *cookie, struct sockaddr *name,
225 224 socklen_t *namelen, cred_t *cr)
226 225 {
227 226 _NOTE(ARGUNUSED(cookie, name, namelen, cr));
228 227
229 228 sof_bypass(handle);
230 229 return (SOF_RVAL_CONTINUE);
231 230 }
232 231
233 232 static void
234 233 kssl_mblk_prop_cb(sof_handle_t handle, void *cookie, ssize_t *maxblk,
235 234 ushort_t *wroff, ushort_t *tail)
236 235 {
237 236 ksslf_t *kssl = (ksslf_t *)cookie;
238 237
239 238 _NOTE(ARGUNUSED(handle));
240 239
241 240 /* only care about passively opened sockets */
242 241 if (kssl == NULL || !kssl->ksslf_pending)
243 242 return;
244 243 /*
245 244 * If this is endpoint is handling SSL, then reserve extra
246 245 * offset and space at the end. Also have sockfs allocate
247 246 * SSL3_MAX_RECORD_LEN packets, overriding the previous setting.
248 247 * The extra cost of signing and encrypting multiple MSS-size
249 248 * records (12 of them with Ethernet), instead of a single
250 249 * contiguous one by the stream head largely outweighs the
251 250 * statistical reduction of ACKs, when applicable. The peer
252 251 * will also save on decryption and verification costs.
253 252 */
254 253 if (*maxblk == INFPSZ || *maxblk > SSL3_MAX_RECORD_LEN)
255 254 *maxblk = SSL3_MAX_RECORD_LEN;
256 255 else
257 256 kssl_set_mss(kssl->ksslf_ctx, *maxblk);
258 257 *wroff += SSL3_WROFFSET;
259 258 *tail += SSL3_MAX_TAIL_LEN;
260 259 }
261 260
262 261 sof_rval_t
263 262 kssl_getsockname_cb(sof_handle_t handle, void *cookie, struct sockaddr *addr,
264 263 socklen_t *addrlen, cred_t *cr)
265 264 {
266 265 ksslf_t *kssl = (ksslf_t *)cookie;
267 266
268 267 _NOTE(ARGUNUSED(handle, cr));
269 268
270 269 if (kssl == NULL)
271 270 return (SOF_RVAL_CONTINUE);
272 271
273 272 if (*addrlen < kssl->ksslf_laddrlen)
274 273 return (SOF_RVAL_EINVAL);
275 274
276 275 *addrlen = kssl->ksslf_laddrlen;
277 276 bcopy(&kssl->ksslf_laddr, addr, kssl->ksslf_laddrlen);
278 277
279 278 return (SOF_RVAL_RETURN);
280 279 }
281 280
282 281 /*
283 282 * Called for every packet sent to the protocol.
284 283 * If the message is successfully processed, then it is returned.
285 284 */
286 285 mblk_t *
287 286 kssl_data_out_cb(sof_handle_t handle, void *cookie, mblk_t *mp,
288 287 struct nmsghdr *msg, cred_t *cr, sof_rval_t *rv)
289 288 {
290 289 ksslf_t *kssl = (ksslf_t *)cookie;
291 290 mblk_t *recmp;
292 291
293 292 _NOTE(ARGUNUSED(handle, msg, cr));
294 293
295 294 *rv = SOF_RVAL_CONTINUE;
296 295 if (kssl == NULL || kssl->ksslf_ctx == NULL)
297 296 return (mp);
298 297
299 298 if ((recmp = kssl_build_record(kssl->ksslf_ctx, mp)) == NULL) {
300 299 freemsg(mp);
301 300 *rv = SOF_RVAL_EINVAL;
302 301 return (NULL);
303 302 }
304 303 return (recmp);
305 304 }
306 305
307 306 /*
308 307 * Called from shutdown() processing. This will produce close_notify message
309 308 * to indicate the end of data to the client.
310 309 */
311 310 sof_rval_t
312 311 kssl_shutdown_cb(sof_handle_t handle, void *cookie, int *howp, cred_t *cr)
313 312 {
314 313 ksslf_t *kssl = (ksslf_t *)cookie;
315 314 mblk_t *outmp;
316 315 boolean_t flowctrld;
317 316 struct nmsghdr msg;
318 317
319 318 _NOTE(ARGUNUSED(cr));
320 319
321 320 if (kssl == NULL || kssl->ksslf_ctx == NULL)
322 321 return (SOF_RVAL_CONTINUE);
323 322
324 323 /*
325 324 * We only want to send close_notify when doing SHUT_WR/SHUT_RDWR
326 325 * because it signals that server is done writing data.
327 326 */
328 327 if (*howp == SHUT_RD)
329 328 return (SOF_RVAL_CONTINUE);
330 329
331 330 /* Go on if we fail to build the record. */
332 331 if ((outmp = kssl_build_record(kssl->ksslf_ctx, NULL)) == NULL)
333 332 return (SOF_RVAL_CONTINUE);
334 333
335 334 bzero(&msg, sizeof (msg));
336 335 (void) sof_inject_data_out(handle, outmp, &msg,
337 336 &flowctrld);
338 337
339 338 return (SOF_RVAL_CONTINUE);
340 339 }
341 340
342 341 /*
343 342 * Called for each incoming segment.
344 343 *
345 344 * A packet may carry multiple SSL records, so the function calls
346 345 * kssl_input() in a loop, until all records are handled.
347 346 */
348 347 mblk_t *
349 348 kssl_data_in_cb(sof_handle_t handle, void *cookie, mblk_t *mp, int flags,
350 349 size_t *lenp)
351 350 {
352 351 ksslf_t *kssl = cookie;
353 352 kssl_cmd_t kssl_cmd;
354 353 mblk_t *outmp, *retmp = NULL, **tail = &retmp;
355 354 boolean_t more = B_FALSE;
356 355 boolean_t flowctrld;
357 356
358 357 _NOTE(ARGUNUSED(flags));
359 358
360 359 if (kssl == NULL || kssl->ksslf_ctx == NULL) {
361 360 sof_bypass(handle);
362 361 return (mp);
363 362 }
364 363
365 364 *lenp = 0;
366 365 do {
367 366 kssl_cmd = kssl_input(kssl->ksslf_ctx, mp, &outmp,
368 367 &more, kssl_input_callback, (void *)handle);
369 368
370 369 switch (kssl_cmd) {
371 370 case KSSL_CMD_SEND: {
372 371 struct nmsghdr msg;
373 372
374 373 DTRACE_PROBE(kssl_cmd_send);
375 374 bzero(&msg, sizeof (msg));
376 375 (void) sof_inject_data_out(handle, outmp, &msg,
377 376 &flowctrld);
378 377 }
379 378 /* FALLTHROUGH */
380 379 case KSSL_CMD_NONE:
381 380 DTRACE_PROBE(kssl_cmd_none);
382 381 if (kssl->ksslf_pending) {
383 382 kssl->ksslf_pending = B_FALSE;
384 383 sof_newconn_ready(handle);
385 384 }
386 385 break;
387 386
388 387 case KSSL_CMD_QUEUED:
389 388 DTRACE_PROBE(kssl_cmd_queued);
390 389 break;
391 390
392 391 case KSSL_CMD_DELIVER_PROXY:
393 392 case KSSL_CMD_DELIVER_SSL:
394 393 DTRACE_PROBE(kssl_cmd_proxy__ssl);
395 394 /*
396 395 * We're at a phase where records are sent upstreams,
397 396 * past the handshake
398 397 */
399 398 kssl->ksslf_inhandshake = B_FALSE;
400 399
401 400 *tail = outmp;
402 401 *lenp += MBLKL(outmp);
403 402 while (outmp->b_cont != NULL) {
404 403 outmp = outmp->b_cont;
405 404 *lenp += MBLKL(outmp);
406 405 }
407 406 tail = &outmp->b_cont;
408 407 break;
409 408
410 409 case KSSL_CMD_NOT_SUPPORTED: {
411 410 ksslf_t *listener = kssl->ksslf_listener;
412 411 sof_handle_t fallback;
413 412
414 413 DTRACE_PROBE(kssl_cmd_not_supported);
415 414 /*
416 415 * Stop the SSL processing by the proxy, and
417 416 * switch to the userland SSL
418 417 */
419 418 if (kssl->ksslf_pending) {
420 419 kssl->ksslf_pending = B_FALSE;
421 420
422 421 DTRACE_PROBE1(kssl_no_can_do, sof_handle_t,
423 422 handle);
424 423
425 424 sof_bypass(handle);
426 425
427 426 ASSERT(listener->ksslf_ent != NULL);
428 427 fallback =
429 428 kssl_find_fallback(listener->ksslf_ent);
430 429 /*
431 430 * No fallback: the remote will timeout and
432 431 * disconnect.
433 432 */
434 433 if (fallback != NULL &&
435 434 sof_newconn_move(handle, fallback))
436 435 sof_newconn_ready(handle);
437 436 }
438 437 if (mp != NULL) {
439 438 *tail = mp;
440 439 *lenp += MBLKL(mp);
441 440 while (mp->b_cont != NULL) {
442 441 mp = mp->b_cont;
443 442 *lenp += MBLKL(mp);
444 443 }
445 444 tail = &mp->b_cont;
446 445 }
447 446 break;
448 447 }
449 448 }
450 449 mp = NULL;
451 450 } while (more);
452 451
453 452 return (retmp);
454 453 }
455 454
456 455 /*
457 456 * Process queued data before it's copied by the user.
458 457 *
459 458 * If the message is successfully processed, then it is returned.
460 459 * A failed message will be freed.
461 460 */
462 461 mblk_t *
463 462 kssl_data_in_proc_cb(sof_handle_t handle, void *cookie, mblk_t *mp,
464 463 cred_t *cr, size_t *lenp)
465 464 {
466 465 ksslf_t *kssl = (ksslf_t *)cookie;
467 466 kssl_cmd_t kssl_cmd;
468 467 mblk_t *out;
469 468
470 469 _NOTE(ARGUNUSED(cr));
471 470
472 471 if (kssl == NULL || kssl->ksslf_ctx)
473 472 return (mp);
474 473
475 474 *lenp = 0;
476 475
477 476 kssl_cmd = kssl_handle_mblk(kssl->ksslf_ctx, &mp, &out);
478 477
479 478 switch (kssl_cmd) {
480 479 case KSSL_CMD_NONE:
481 480 return (NULL);
482 481 case KSSL_CMD_DELIVER_PROXY:
483 482 *lenp = msgdsize(mp);
484 483 return (mp);
485 484 case KSSL_CMD_SEND: {
486 485 struct nmsghdr msg;
487 486 boolean_t flowctrld;
488 487
489 488 ASSERT(out != NULL);
490 489 bzero(&msg, sizeof (msg));
491 490
492 491 (void) sof_inject_data_out(handle, out, &msg,
493 492 &flowctrld);
494 493 return (NULL);
495 494 }
496 495 default:
497 496 /* transient error. */
498 497 return (NULL);
499 498 }
500 499 }
501 500
502 501 /*
503 502 * Continue processing the incoming flow after an asynchronous callback.
504 503 */
505 504 static void
506 505 kssl_input_asynch(void *arg)
507 506 {
508 507 sof_handle_t handle = (sof_handle_t)arg;
509 508 ksslf_t *kssl = (ksslf_t *)sof_get_cookie(handle);
510 509 size_t len = 0;
511 510 boolean_t flowctrld;
512 511 mblk_t *mp;
513 512
514 513 if ((mp = kssl_data_in_cb(handle, kssl, NULL, 0, &len)) != NULL) {
515 514 ASSERT(len != 0);
516 515 (void) sof_inject_data_in(handle, mp, len, 0, &flowctrld);
517 516 }
518 517 kssl_async_done(kssl->ksslf_ctx);
519 518 }
520 519
521 520 /*
522 521 * Callback function for the cases kssl_input() had to submit an asynchronous
523 522 * job and need to come back when done to carry on the input processing.
524 523 * This routine follows the conentions of timeout and interrupt handlers.
525 524 * (no blocking, ...)
526 525 */
527 526 static void
528 527 kssl_input_callback(void *arg, mblk_t *mp, kssl_cmd_t kssl_cmd)
529 528 {
530 529 sof_handle_t handle = (sof_handle_t)arg;
531 530 ksslf_t *kssl = (ksslf_t *)sof_get_cookie(handle);
532 531 boolean_t flowctrld;
533 532
534 533 ASSERT(kssl != NULL);
535 534
536 535 switch (kssl_cmd) {
537 536 case KSSL_CMD_SEND: {
538 537 struct nmsghdr msg;
539 538
540 539 if (mp == NULL)
541 540 break;
542 541 bzero(&msg, sizeof (msg));
543 542
544 543 (void) sof_inject_data_out(handle, mp, &msg, &flowctrld);
545 544 }
546 545 /* FALLTHROUGH */
547 546 case KSSL_CMD_NONE:
548 547 break;
549 548
550 549 case KSSL_CMD_DELIVER_PROXY:
551 550 case KSSL_CMD_DELIVER_SSL:
552 551 (void) sof_inject_data_in(handle, mp, msgdsize(mp), 0,
553 552 &flowctrld);
554 553 break;
555 554
556 555 case KSSL_CMD_NOT_SUPPORTED:
557 556 /* Stop the SSL processing */
558 557 sof_bypass(handle);
559 558 }
560 559 /*
561 560 * Process any input that may have accumulated while we're waiting for
562 561 * the call-back. This must be done by a taskq because kssl_input might
563 562 * block when handling client_finish messages.
564 563 */
565 564 if (taskq_dispatch(system_taskq, kssl_input_asynch, handle,
566 565 TQ_NOSLEEP) == NULL) {
567 566 DTRACE_PROBE(kssl_err__taskq_dispatch_failed);
568 567 kssl_async_done(kssl->ksslf_ctx);
569 568 }
570 569 }
571 570
572 571 sof_ops_t ksslf_ops = {
573 572 .sofop_attach_passive = kssl_attach_passive_cb,
574 573 .sofop_detach = kssl_detach_cb,
575 574 .sofop_bind = kssl_bind_cb,
576 575 .sofop_connect = kssl_connect_cb,
577 576 .sofop_listen = kssl_listen_cb,
578 577 .sofop_data_in = kssl_data_in_cb,
579 578 .sofop_data_in_proc = kssl_data_in_proc_cb,
580 579 .sofop_data_out = kssl_data_out_cb,
581 580 .sofop_mblk_prop = kssl_mblk_prop_cb,
582 581 .sofop_getsockname = kssl_getsockname_cb,
583 582 .sofop_shutdown = kssl_shutdown_cb,
584 583 };
585 584
586 585 int
587 586 _init(void)
588 587 {
589 588 int error;
590 589
591 590 if ((error = sof_register(SOF_VERSION, KSSL_FILNAME,
592 591 &ksslf_ops, 0)) != 0)
593 592 return (error);
594 593 if ((error = mod_install(&ksslf_modlinkage)) != 0)
595 594 (void) sof_unregister(KSSL_FILNAME);
596 595
597 596 return (error);
598 597 }
599 598
600 599 int
601 600 _fini(void)
602 601 {
603 602 int error;
604 603
605 604 if ((error = sof_unregister(KSSL_FILNAME)) != 0)
606 605 return (error);
607 606
608 607 return (mod_remove(&ksslf_modlinkage));
609 608 }
610 609
611 610 int
612 611 _info(struct modinfo *modinfop)
613 612 {
614 613 return (mod_info(&ksslf_modlinkage, modinfop));
615 614 }
↓ open down ↓ |
557 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX