diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/net/netiucv.c | 1314 |
1 files changed, 652 insertions, 662 deletions
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 3346088f47e0..6387b483f2bf 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * IUCV network driver | 2 | * IUCV network driver |
3 | * | 3 | * |
4 | * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation | 4 | * Copyright 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation |
5 | * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) | 5 | * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) |
6 | * | 6 | * |
7 | * Sysfs integration and all bugs therein by Cornelia Huck | 7 | * Sysfs integration and all bugs therein by Cornelia Huck |
@@ -58,13 +58,94 @@ | |||
58 | #include <asm/io.h> | 58 | #include <asm/io.h> |
59 | #include <asm/uaccess.h> | 59 | #include <asm/uaccess.h> |
60 | 60 | ||
61 | #include "iucv.h" | 61 | #include <net/iucv/iucv.h> |
62 | #include "fsm.h" | 62 | #include "fsm.h" |
63 | 63 | ||
64 | MODULE_AUTHOR | 64 | MODULE_AUTHOR |
65 | ("(C) 2001 IBM Corporation by Fritz Elfert (felfert@millenux.com)"); | 65 | ("(C) 2001 IBM Corporation by Fritz Elfert (felfert@millenux.com)"); |
66 | MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver"); | 66 | MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver"); |
67 | 67 | ||
68 | /** | ||
69 | * Debug Facility stuff | ||
70 | */ | ||
71 | #define IUCV_DBF_SETUP_NAME "iucv_setup" | ||
72 | #define IUCV_DBF_SETUP_LEN 32 | ||
73 | #define IUCV_DBF_SETUP_PAGES 2 | ||
74 | #define IUCV_DBF_SETUP_NR_AREAS 1 | ||
75 | #define IUCV_DBF_SETUP_LEVEL 3 | ||
76 | |||
77 | #define IUCV_DBF_DATA_NAME "iucv_data" | ||
78 | #define IUCV_DBF_DATA_LEN 128 | ||
79 | #define IUCV_DBF_DATA_PAGES 2 | ||
80 | #define IUCV_DBF_DATA_NR_AREAS 1 | ||
81 | #define IUCV_DBF_DATA_LEVEL 2 | ||
82 | |||
83 | #define IUCV_DBF_TRACE_NAME "iucv_trace" | ||
84 | #define IUCV_DBF_TRACE_LEN 16 | ||
85 | #define IUCV_DBF_TRACE_PAGES 4 | ||
86 | #define IUCV_DBF_TRACE_NR_AREAS 1 | ||
87 | #define IUCV_DBF_TRACE_LEVEL 3 | ||
88 | |||
89 | #define IUCV_DBF_TEXT(name,level,text) \ | ||
90 | do { \ | ||
91 | debug_text_event(iucv_dbf_##name,level,text); \ | ||
92 | } while (0) | ||
93 | |||
94 | #define IUCV_DBF_HEX(name,level,addr,len) \ | ||
95 | do { \ | ||
96 | debug_event(iucv_dbf_##name,level,(void*)(addr),len); \ | ||
97 | } while (0) | ||
98 | |||
99 | DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf); | ||
100 | |||
101 | #define IUCV_DBF_TEXT_(name,level,text...) \ | ||
102 | do { \ | ||
103 | char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \ | ||
104 | sprintf(iucv_dbf_txt_buf, text); \ | ||
105 | debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \ | ||
106 | put_cpu_var(iucv_dbf_txt_buf); \ | ||
107 | } while (0) | ||
108 | |||
109 | #define IUCV_DBF_SPRINTF(name,level,text...) \ | ||
110 | do { \ | ||
111 | debug_sprintf_event(iucv_dbf_trace, level, ##text ); \ | ||
112 | debug_sprintf_event(iucv_dbf_trace, level, text ); \ | ||
113 | } while (0) | ||
114 | |||
115 | /** | ||
116 | * some more debug stuff | ||
117 | */ | ||
118 | #define IUCV_HEXDUMP16(importance,header,ptr) \ | ||
119 | PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ | ||
120 | "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ | ||
121 | *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \ | ||
122 | *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \ | ||
123 | *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \ | ||
124 | *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \ | ||
125 | *(((char*)ptr)+12),*(((char*)ptr)+13), \ | ||
126 | *(((char*)ptr)+14),*(((char*)ptr)+15)); \ | ||
127 | PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ | ||
128 | "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ | ||
129 | *(((char*)ptr)+16),*(((char*)ptr)+17), \ | ||
130 | *(((char*)ptr)+18),*(((char*)ptr)+19), \ | ||
131 | *(((char*)ptr)+20),*(((char*)ptr)+21), \ | ||
132 | *(((char*)ptr)+22),*(((char*)ptr)+23), \ | ||
133 | *(((char*)ptr)+24),*(((char*)ptr)+25), \ | ||
134 | *(((char*)ptr)+26),*(((char*)ptr)+27), \ | ||
135 | *(((char*)ptr)+28),*(((char*)ptr)+29), \ | ||
136 | *(((char*)ptr)+30),*(((char*)ptr)+31)); | ||
137 | |||
138 | static inline void iucv_hex_dump(unsigned char *buf, size_t len) | ||
139 | { | ||
140 | size_t i; | ||
141 | |||
142 | for (i = 0; i < len; i++) { | ||
143 | if (i && !(i % 16)) | ||
144 | printk("\n"); | ||
145 | printk("%02x ", *(buf + i)); | ||
146 | } | ||
147 | printk("\n"); | ||
148 | } | ||
68 | 149 | ||
69 | #define PRINTK_HEADER " iucv: " /* for debugging */ | 150 | #define PRINTK_HEADER " iucv: " /* for debugging */ |
70 | 151 | ||
@@ -73,6 +154,25 @@ static struct device_driver netiucv_driver = { | |||
73 | .bus = &iucv_bus, | 154 | .bus = &iucv_bus, |
74 | }; | 155 | }; |
75 | 156 | ||
157 | static int netiucv_callback_connreq(struct iucv_path *, | ||
158 | u8 ipvmid[8], u8 ipuser[16]); | ||
159 | static void netiucv_callback_connack(struct iucv_path *, u8 ipuser[16]); | ||
160 | static void netiucv_callback_connrej(struct iucv_path *, u8 ipuser[16]); | ||
161 | static void netiucv_callback_connsusp(struct iucv_path *, u8 ipuser[16]); | ||
162 | static void netiucv_callback_connres(struct iucv_path *, u8 ipuser[16]); | ||
163 | static void netiucv_callback_rx(struct iucv_path *, struct iucv_message *); | ||
164 | static void netiucv_callback_txdone(struct iucv_path *, struct iucv_message *); | ||
165 | |||
166 | static struct iucv_handler netiucv_handler = { | ||
167 | .path_pending = netiucv_callback_connreq, | ||
168 | .path_complete = netiucv_callback_connack, | ||
169 | .path_severed = netiucv_callback_connrej, | ||
170 | .path_quiesced = netiucv_callback_connsusp, | ||
171 | .path_resumed = netiucv_callback_connres, | ||
172 | .message_pending = netiucv_callback_rx, | ||
173 | .message_complete = netiucv_callback_txdone | ||
174 | }; | ||
175 | |||
76 | /** | 176 | /** |
77 | * Per connection profiling data | 177 | * Per connection profiling data |
78 | */ | 178 | */ |
@@ -92,9 +192,8 @@ struct connection_profile { | |||
92 | * Representation of one iucv connection | 192 | * Representation of one iucv connection |
93 | */ | 193 | */ |
94 | struct iucv_connection { | 194 | struct iucv_connection { |
95 | struct iucv_connection *next; | 195 | struct list_head list; |
96 | iucv_handle_t handle; | 196 | struct iucv_path *path; |
97 | __u16 pathid; | ||
98 | struct sk_buff *rx_buff; | 197 | struct sk_buff *rx_buff; |
99 | struct sk_buff *tx_buff; | 198 | struct sk_buff *tx_buff; |
100 | struct sk_buff_head collect_queue; | 199 | struct sk_buff_head collect_queue; |
@@ -112,12 +211,9 @@ struct iucv_connection { | |||
112 | /** | 211 | /** |
113 | * Linked list of all connection structs. | 212 | * Linked list of all connection structs. |
114 | */ | 213 | */ |
115 | struct iucv_connection_struct { | 214 | static struct list_head iucv_connection_list = |
116 | struct iucv_connection *iucv_connections; | 215 | LIST_HEAD_INIT(iucv_connection_list); |
117 | rwlock_t iucv_rwlock; | 216 | static rwlock_t iucv_connection_rwlock = RW_LOCK_UNLOCKED; |
118 | }; | ||
119 | |||
120 | static struct iucv_connection_struct iucv_conns; | ||
121 | 217 | ||
122 | /** | 218 | /** |
123 | * Representation of event-data for the | 219 | * Representation of event-data for the |
@@ -142,11 +238,11 @@ struct netiucv_priv { | |||
142 | /** | 238 | /** |
143 | * Link level header for a packet. | 239 | * Link level header for a packet. |
144 | */ | 240 | */ |
145 | typedef struct ll_header_t { | 241 | struct ll_header { |
146 | __u16 next; | 242 | u16 next; |
147 | } ll_header; | 243 | }; |
148 | 244 | ||
149 | #define NETIUCV_HDRLEN (sizeof(ll_header)) | 245 | #define NETIUCV_HDRLEN (sizeof(struct ll_header)) |
150 | #define NETIUCV_BUFSIZE_MAX 32768 | 246 | #define NETIUCV_BUFSIZE_MAX 32768 |
151 | #define NETIUCV_BUFSIZE_DEFAULT NETIUCV_BUFSIZE_MAX | 247 | #define NETIUCV_BUFSIZE_DEFAULT NETIUCV_BUFSIZE_MAX |
152 | #define NETIUCV_MTU_MAX (NETIUCV_BUFSIZE_MAX - NETIUCV_HDRLEN) | 248 | #define NETIUCV_MTU_MAX (NETIUCV_BUFSIZE_MAX - NETIUCV_HDRLEN) |
@@ -158,36 +254,26 @@ typedef struct ll_header_t { | |||
158 | * Compatibility macros for busy handling | 254 | * Compatibility macros for busy handling |
159 | * of network devices. | 255 | * of network devices. |
160 | */ | 256 | */ |
161 | static __inline__ void netiucv_clear_busy(struct net_device *dev) | 257 | static inline void netiucv_clear_busy(struct net_device *dev) |
162 | { | 258 | { |
163 | clear_bit(0, &(((struct netiucv_priv *)dev->priv)->tbusy)); | 259 | struct netiucv_priv *priv = netdev_priv(dev); |
260 | clear_bit(0, &priv->tbusy); | ||
164 | netif_wake_queue(dev); | 261 | netif_wake_queue(dev); |
165 | } | 262 | } |
166 | 263 | ||
167 | static __inline__ int netiucv_test_and_set_busy(struct net_device *dev) | 264 | static inline int netiucv_test_and_set_busy(struct net_device *dev) |
168 | { | 265 | { |
266 | struct netiucv_priv *priv = netdev_priv(dev); | ||
169 | netif_stop_queue(dev); | 267 | netif_stop_queue(dev); |
170 | return test_and_set_bit(0, &((struct netiucv_priv *)dev->priv)->tbusy); | 268 | return test_and_set_bit(0, &priv->tbusy); |
171 | } | 269 | } |
172 | 270 | ||
173 | static __u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | 271 | static u8 iucvMagic[16] = { |
174 | static __u8 iucvMagic[16] = { | ||
175 | 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, | 272 | 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, |
176 | 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 | 273 | 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 |
177 | }; | 274 | }; |
178 | 275 | ||
179 | /** | 276 | /** |
180 | * This mask means the 16-byte IUCV "magic" and the origin userid must | ||
181 | * match exactly as specified in order to give connection_pending() | ||
182 | * control. | ||
183 | */ | ||
184 | static __u8 netiucv_mask[] = { | ||
185 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
186 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
187 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff | ||
188 | }; | ||
189 | |||
190 | /** | ||
191 | * Convert an iucv userId to its printable | 277 | * Convert an iucv userId to its printable |
192 | * form (strip whitespace at end). | 278 | * form (strip whitespace at end). |
193 | * | 279 | * |
@@ -195,8 +281,7 @@ static __u8 netiucv_mask[] = { | |||
195 | * | 281 | * |
196 | * @returns The printable string (static data!!) | 282 | * @returns The printable string (static data!!) |
197 | */ | 283 | */ |
198 | static __inline__ char * | 284 | static inline char *netiucv_printname(char *name) |
199 | netiucv_printname(char *name) | ||
200 | { | 285 | { |
201 | static char tmp[9]; | 286 | static char tmp[9]; |
202 | char *p = tmp; | 287 | char *p = tmp; |
@@ -379,8 +464,7 @@ static debug_info_t *iucv_dbf_trace = NULL; | |||
379 | 464 | ||
380 | DEFINE_PER_CPU(char[256], iucv_dbf_txt_buf); | 465 | DEFINE_PER_CPU(char[256], iucv_dbf_txt_buf); |
381 | 466 | ||
382 | static void | 467 | static void iucv_unregister_dbf_views(void) |
383 | iucv_unregister_dbf_views(void) | ||
384 | { | 468 | { |
385 | if (iucv_dbf_setup) | 469 | if (iucv_dbf_setup) |
386 | debug_unregister(iucv_dbf_setup); | 470 | debug_unregister(iucv_dbf_setup); |
@@ -389,8 +473,7 @@ iucv_unregister_dbf_views(void) | |||
389 | if (iucv_dbf_trace) | 473 | if (iucv_dbf_trace) |
390 | debug_unregister(iucv_dbf_trace); | 474 | debug_unregister(iucv_dbf_trace); |
391 | } | 475 | } |
392 | static int | 476 | static int iucv_register_dbf_views(void) |
393 | iucv_register_dbf_views(void) | ||
394 | { | 477 | { |
395 | iucv_dbf_setup = debug_register(IUCV_DBF_SETUP_NAME, | 478 | iucv_dbf_setup = debug_register(IUCV_DBF_SETUP_NAME, |
396 | IUCV_DBF_SETUP_PAGES, | 479 | IUCV_DBF_SETUP_PAGES, |
@@ -422,125 +505,111 @@ iucv_register_dbf_views(void) | |||
422 | return 0; | 505 | return 0; |
423 | } | 506 | } |
424 | 507 | ||
425 | /** | 508 | /* |
426 | * Callback-wrappers, called from lowlevel iucv layer. | 509 | * Callback-wrappers, called from lowlevel iucv layer. |
427 | *****************************************************************************/ | 510 | */ |
428 | 511 | ||
429 | static void | 512 | static void netiucv_callback_rx(struct iucv_path *path, |
430 | netiucv_callback_rx(iucv_MessagePending *eib, void *pgm_data) | 513 | struct iucv_message *msg) |
431 | { | 514 | { |
432 | struct iucv_connection *conn = (struct iucv_connection *)pgm_data; | 515 | struct iucv_connection *conn = path->private; |
433 | struct iucv_event ev; | 516 | struct iucv_event ev; |
434 | 517 | ||
435 | ev.conn = conn; | 518 | ev.conn = conn; |
436 | ev.data = (void *)eib; | 519 | ev.data = msg; |
437 | |||
438 | fsm_event(conn->fsm, CONN_EVENT_RX, &ev); | 520 | fsm_event(conn->fsm, CONN_EVENT_RX, &ev); |
439 | } | 521 | } |
440 | 522 | ||
441 | static void | 523 | static void netiucv_callback_txdone(struct iucv_path *path, |
442 | netiucv_callback_txdone(iucv_MessageComplete *eib, void *pgm_data) | 524 | struct iucv_message *msg) |
443 | { | 525 | { |
444 | struct iucv_connection *conn = (struct iucv_connection *)pgm_data; | 526 | struct iucv_connection *conn = path->private; |
445 | struct iucv_event ev; | 527 | struct iucv_event ev; |
446 | 528 | ||
447 | ev.conn = conn; | 529 | ev.conn = conn; |
448 | ev.data = (void *)eib; | 530 | ev.data = msg; |
449 | fsm_event(conn->fsm, CONN_EVENT_TXDONE, &ev); | 531 | fsm_event(conn->fsm, CONN_EVENT_TXDONE, &ev); |
450 | } | 532 | } |
451 | 533 | ||
452 | static void | 534 | static void netiucv_callback_connack(struct iucv_path *path, u8 ipuser[16]) |
453 | netiucv_callback_connack(iucv_ConnectionComplete *eib, void *pgm_data) | ||
454 | { | 535 | { |
455 | struct iucv_connection *conn = (struct iucv_connection *)pgm_data; | 536 | struct iucv_connection *conn = path->private; |
456 | struct iucv_event ev; | ||
457 | 537 | ||
458 | ev.conn = conn; | 538 | fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, conn); |
459 | ev.data = (void *)eib; | ||
460 | fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, &ev); | ||
461 | } | 539 | } |
462 | 540 | ||
463 | static void | 541 | static int netiucv_callback_connreq(struct iucv_path *path, |
464 | netiucv_callback_connreq(iucv_ConnectionPending *eib, void *pgm_data) | 542 | u8 ipvmid[8], u8 ipuser[16]) |
465 | { | 543 | { |
466 | struct iucv_connection *conn = (struct iucv_connection *)pgm_data; | 544 | struct iucv_connection *conn = path->private; |
467 | struct iucv_event ev; | 545 | struct iucv_event ev; |
546 | int rc; | ||
468 | 547 | ||
469 | ev.conn = conn; | 548 | if (memcmp(iucvMagic, ipuser, sizeof(ipuser))) |
470 | ev.data = (void *)eib; | 549 | /* ipuser must match iucvMagic. */ |
471 | fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev); | 550 | return -EINVAL; |
551 | rc = -EINVAL; | ||
552 | read_lock_bh(&iucv_connection_rwlock); | ||
553 | list_for_each_entry(conn, &iucv_connection_list, list) { | ||
554 | if (strncmp(ipvmid, conn->userid, 8)) | ||
555 | continue; | ||
556 | /* Found a matching connection for this path. */ | ||
557 | conn->path = path; | ||
558 | ev.conn = conn; | ||
559 | ev.data = path; | ||
560 | fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev); | ||
561 | rc = 0; | ||
562 | } | ||
563 | read_unlock_bh(&iucv_connection_rwlock); | ||
564 | return rc; | ||
472 | } | 565 | } |
473 | 566 | ||
474 | static void | 567 | static void netiucv_callback_connrej(struct iucv_path *path, u8 ipuser[16]) |
475 | netiucv_callback_connrej(iucv_ConnectionSevered *eib, void *pgm_data) | ||
476 | { | 568 | { |
477 | struct iucv_connection *conn = (struct iucv_connection *)pgm_data; | 569 | struct iucv_connection *conn = path->private; |
478 | struct iucv_event ev; | ||
479 | 570 | ||
480 | ev.conn = conn; | 571 | fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, conn); |
481 | ev.data = (void *)eib; | ||
482 | fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, &ev); | ||
483 | } | 572 | } |
484 | 573 | ||
485 | static void | 574 | static void netiucv_callback_connsusp(struct iucv_path *path, u8 ipuser[16]) |
486 | netiucv_callback_connsusp(iucv_ConnectionQuiesced *eib, void *pgm_data) | ||
487 | { | 575 | { |
488 | struct iucv_connection *conn = (struct iucv_connection *)pgm_data; | 576 | struct iucv_connection *conn = path->private; |
489 | struct iucv_event ev; | ||
490 | 577 | ||
491 | ev.conn = conn; | 578 | fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, conn); |
492 | ev.data = (void *)eib; | ||
493 | fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, &ev); | ||
494 | } | 579 | } |
495 | 580 | ||
496 | static void | 581 | static void netiucv_callback_connres(struct iucv_path *path, u8 ipuser[16]) |
497 | netiucv_callback_connres(iucv_ConnectionResumed *eib, void *pgm_data) | ||
498 | { | 582 | { |
499 | struct iucv_connection *conn = (struct iucv_connection *)pgm_data; | 583 | struct iucv_connection *conn = path->private; |
500 | struct iucv_event ev; | ||
501 | 584 | ||
502 | ev.conn = conn; | 585 | fsm_event(conn->fsm, CONN_EVENT_CONN_RES, conn); |
503 | ev.data = (void *)eib; | 586 | } |
504 | fsm_event(conn->fsm, CONN_EVENT_CONN_RES, &ev); | ||
505 | } | ||
506 | |||
507 | static iucv_interrupt_ops_t netiucv_ops = { | ||
508 | .ConnectionPending = netiucv_callback_connreq, | ||
509 | .ConnectionComplete = netiucv_callback_connack, | ||
510 | .ConnectionSevered = netiucv_callback_connrej, | ||
511 | .ConnectionQuiesced = netiucv_callback_connsusp, | ||
512 | .ConnectionResumed = netiucv_callback_connres, | ||
513 | .MessagePending = netiucv_callback_rx, | ||
514 | .MessageComplete = netiucv_callback_txdone | ||
515 | }; | ||
516 | 587 | ||
517 | /** | 588 | /** |
518 | * Dummy NOP action for all statemachines | 589 | * Dummy NOP action for all statemachines |
519 | */ | 590 | */ |
520 | static void | 591 | static void fsm_action_nop(fsm_instance *fi, int event, void *arg) |
521 | fsm_action_nop(fsm_instance *fi, int event, void *arg) | ||
522 | { | 592 | { |
523 | } | 593 | } |
524 | 594 | ||
525 | /** | 595 | /* |
526 | * Actions of the connection statemachine | 596 | * Actions of the connection statemachine |
527 | *****************************************************************************/ | 597 | */ |
528 | 598 | ||
529 | /** | 599 | /** |
530 | * Helper function for conn_action_rx() | 600 | * netiucv_unpack_skb |
531 | * Unpack a just received skb and hand it over to | 601 | * @conn: The connection where this skb has been received. |
532 | * upper layers. | 602 | * @pskb: The received skb. |
533 | * | 603 | * |
534 | * @param conn The connection where this skb has been received. | 604 | * Unpack a just received skb and hand it over to upper layers. |
535 | * @param pskb The received skb. | 605 | * Helper function for conn_action_rx. |
536 | */ | 606 | */ |
537 | //static __inline__ void | 607 | static void netiucv_unpack_skb(struct iucv_connection *conn, |
538 | static void | 608 | struct sk_buff *pskb) |
539 | netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb) | ||
540 | { | 609 | { |
541 | struct net_device *dev = conn->netdev; | 610 | struct net_device *dev = conn->netdev; |
542 | struct netiucv_priv *privptr = dev->priv; | 611 | struct netiucv_priv *privptr = netdev_priv(dev); |
543 | __u16 offset = 0; | 612 | u16 offset = 0; |
544 | 613 | ||
545 | skb_put(pskb, NETIUCV_HDRLEN); | 614 | skb_put(pskb, NETIUCV_HDRLEN); |
546 | pskb->dev = dev; | 615 | pskb->dev = dev; |
@@ -549,7 +618,7 @@ netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb) | |||
549 | 618 | ||
550 | while (1) { | 619 | while (1) { |
551 | struct sk_buff *skb; | 620 | struct sk_buff *skb; |
552 | ll_header *header = (ll_header *)pskb->data; | 621 | struct ll_header *header = (struct ll_header *) pskb->data; |
553 | 622 | ||
554 | if (!header->next) | 623 | if (!header->next) |
555 | break; | 624 | break; |
@@ -595,40 +664,37 @@ netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb) | |||
595 | } | 664 | } |
596 | } | 665 | } |
597 | 666 | ||
598 | static void | 667 | static void conn_action_rx(fsm_instance *fi, int event, void *arg) |
599 | conn_action_rx(fsm_instance *fi, int event, void *arg) | ||
600 | { | 668 | { |
601 | struct iucv_event *ev = (struct iucv_event *)arg; | 669 | struct iucv_event *ev = arg; |
602 | struct iucv_connection *conn = ev->conn; | 670 | struct iucv_connection *conn = ev->conn; |
603 | iucv_MessagePending *eib = (iucv_MessagePending *)ev->data; | 671 | struct iucv_message *msg = ev->data; |
604 | struct netiucv_priv *privptr =(struct netiucv_priv *)conn->netdev->priv; | 672 | struct netiucv_priv *privptr = netdev_priv(conn->netdev); |
605 | |||
606 | __u32 msglen = eib->ln1msg2.ipbfln1f; | ||
607 | int rc; | 673 | int rc; |
608 | 674 | ||
609 | IUCV_DBF_TEXT(trace, 4, __FUNCTION__); | 675 | IUCV_DBF_TEXT(trace, 4, __FUNCTION__); |
610 | 676 | ||
611 | if (!conn->netdev) { | 677 | if (!conn->netdev) { |
612 | /* FRITZ: How to tell iucv LL to drop the msg? */ | 678 | iucv_message_reject(conn->path, msg); |
613 | PRINT_WARN("Received data for unlinked connection\n"); | 679 | PRINT_WARN("Received data for unlinked connection\n"); |
614 | IUCV_DBF_TEXT(data, 2, | 680 | IUCV_DBF_TEXT(data, 2, |
615 | "Received data for unlinked connection\n"); | 681 | "Received data for unlinked connection\n"); |
616 | return; | 682 | return; |
617 | } | 683 | } |
618 | if (msglen > conn->max_buffsize) { | 684 | if (msg->length > conn->max_buffsize) { |
619 | /* FRITZ: How to tell iucv LL to drop the msg? */ | 685 | iucv_message_reject(conn->path, msg); |
620 | privptr->stats.rx_dropped++; | 686 | privptr->stats.rx_dropped++; |
621 | PRINT_WARN("msglen %d > max_buffsize %d\n", | 687 | PRINT_WARN("msglen %d > max_buffsize %d\n", |
622 | msglen, conn->max_buffsize); | 688 | msg->length, conn->max_buffsize); |
623 | IUCV_DBF_TEXT_(data, 2, "msglen %d > max_buffsize %d\n", | 689 | IUCV_DBF_TEXT_(data, 2, "msglen %d > max_buffsize %d\n", |
624 | msglen, conn->max_buffsize); | 690 | msg->length, conn->max_buffsize); |
625 | return; | 691 | return; |
626 | } | 692 | } |
627 | conn->rx_buff->data = conn->rx_buff->tail = conn->rx_buff->head; | 693 | conn->rx_buff->data = conn->rx_buff->tail = conn->rx_buff->head; |
628 | conn->rx_buff->len = 0; | 694 | conn->rx_buff->len = 0; |
629 | rc = iucv_receive(conn->pathid, eib->ipmsgid, eib->iptrgcls, | 695 | rc = iucv_message_receive(conn->path, msg, 0, conn->rx_buff->data, |
630 | conn->rx_buff->data, msglen, NULL, NULL, NULL); | 696 | msg->length, NULL); |
631 | if (rc || msglen < 5) { | 697 | if (rc || msg->length < 5) { |
632 | privptr->stats.rx_errors++; | 698 | privptr->stats.rx_errors++; |
633 | PRINT_WARN("iucv_receive returned %08x\n", rc); | 699 | PRINT_WARN("iucv_receive returned %08x\n", rc); |
634 | IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_receive\n", rc); | 700 | IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_receive\n", rc); |
@@ -637,26 +703,26 @@ conn_action_rx(fsm_instance *fi, int event, void *arg) | |||
637 | netiucv_unpack_skb(conn, conn->rx_buff); | 703 | netiucv_unpack_skb(conn, conn->rx_buff); |
638 | } | 704 | } |
639 | 705 | ||
640 | static void | 706 | static void conn_action_txdone(fsm_instance *fi, int event, void *arg) |
641 | conn_action_txdone(fsm_instance *fi, int event, void *arg) | ||
642 | { | 707 | { |
643 | struct iucv_event *ev = (struct iucv_event *)arg; | 708 | struct iucv_event *ev = arg; |
644 | struct iucv_connection *conn = ev->conn; | 709 | struct iucv_connection *conn = ev->conn; |
645 | iucv_MessageComplete *eib = (iucv_MessageComplete *)ev->data; | 710 | struct iucv_message *msg = ev->data; |
711 | struct iucv_message txmsg; | ||
646 | struct netiucv_priv *privptr = NULL; | 712 | struct netiucv_priv *privptr = NULL; |
647 | /* Shut up, gcc! skb is always below 2G. */ | 713 | u32 single_flag = msg->tag; |
648 | __u32 single_flag = eib->ipmsgtag; | 714 | u32 txbytes = 0; |
649 | __u32 txbytes = 0; | 715 | u32 txpackets = 0; |
650 | __u32 txpackets = 0; | 716 | u32 stat_maxcq = 0; |
651 | __u32 stat_maxcq = 0; | ||
652 | struct sk_buff *skb; | 717 | struct sk_buff *skb; |
653 | unsigned long saveflags; | 718 | unsigned long saveflags; |
654 | ll_header header; | 719 | struct ll_header header; |
720 | int rc; | ||
655 | 721 | ||
656 | IUCV_DBF_TEXT(trace, 4, __FUNCTION__); | 722 | IUCV_DBF_TEXT(trace, 4, __FUNCTION__); |
657 | 723 | ||
658 | if (conn && conn->netdev && conn->netdev->priv) | 724 | if (conn && conn->netdev) |
659 | privptr = (struct netiucv_priv *)conn->netdev->priv; | 725 | privptr = netdev_priv(conn->netdev); |
660 | conn->prof.tx_pending--; | 726 | conn->prof.tx_pending--; |
661 | if (single_flag) { | 727 | if (single_flag) { |
662 | if ((skb = skb_dequeue(&conn->commit_queue))) { | 728 | if ((skb = skb_dequeue(&conn->commit_queue))) { |
@@ -688,56 +754,55 @@ conn_action_txdone(fsm_instance *fi, int event, void *arg) | |||
688 | conn->prof.maxmulti = conn->collect_len; | 754 | conn->prof.maxmulti = conn->collect_len; |
689 | conn->collect_len = 0; | 755 | conn->collect_len = 0; |
690 | spin_unlock_irqrestore(&conn->collect_lock, saveflags); | 756 | spin_unlock_irqrestore(&conn->collect_lock, saveflags); |
691 | if (conn->tx_buff->len) { | 757 | if (conn->tx_buff->len == 0) { |
692 | int rc; | 758 | fsm_newstate(fi, CONN_STATE_IDLE); |
693 | 759 | return; | |
694 | header.next = 0; | 760 | } |
695 | memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, | ||
696 | NETIUCV_HDRLEN); | ||
697 | 761 | ||
698 | conn->prof.send_stamp = xtime; | 762 | header.next = 0; |
699 | rc = iucv_send(conn->pathid, NULL, 0, 0, 0, 0, | 763 | memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN); |
764 | conn->prof.send_stamp = xtime; | ||
765 | txmsg.class = 0; | ||
766 | txmsg.tag = 0; | ||
767 | rc = iucv_message_send(conn->path, &txmsg, 0, 0, | ||
700 | conn->tx_buff->data, conn->tx_buff->len); | 768 | conn->tx_buff->data, conn->tx_buff->len); |
701 | conn->prof.doios_multi++; | 769 | conn->prof.doios_multi++; |
702 | conn->prof.txlen += conn->tx_buff->len; | 770 | conn->prof.txlen += conn->tx_buff->len; |
703 | conn->prof.tx_pending++; | 771 | conn->prof.tx_pending++; |
704 | if (conn->prof.tx_pending > conn->prof.tx_max_pending) | 772 | if (conn->prof.tx_pending > conn->prof.tx_max_pending) |
705 | conn->prof.tx_max_pending = conn->prof.tx_pending; | 773 | conn->prof.tx_max_pending = conn->prof.tx_pending; |
706 | if (rc) { | 774 | if (rc) { |
707 | conn->prof.tx_pending--; | 775 | conn->prof.tx_pending--; |
708 | fsm_newstate(fi, CONN_STATE_IDLE); | ||
709 | if (privptr) | ||
710 | privptr->stats.tx_errors += txpackets; | ||
711 | PRINT_WARN("iucv_send returned %08x\n", rc); | ||
712 | IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc); | ||
713 | } else { | ||
714 | if (privptr) { | ||
715 | privptr->stats.tx_packets += txpackets; | ||
716 | privptr->stats.tx_bytes += txbytes; | ||
717 | } | ||
718 | if (stat_maxcq > conn->prof.maxcqueue) | ||
719 | conn->prof.maxcqueue = stat_maxcq; | ||
720 | } | ||
721 | } else | ||
722 | fsm_newstate(fi, CONN_STATE_IDLE); | 776 | fsm_newstate(fi, CONN_STATE_IDLE); |
777 | if (privptr) | ||
778 | privptr->stats.tx_errors += txpackets; | ||
779 | PRINT_WARN("iucv_send returned %08x\n", rc); | ||
780 | IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc); | ||
781 | } else { | ||
782 | if (privptr) { | ||
783 | privptr->stats.tx_packets += txpackets; | ||
784 | privptr->stats.tx_bytes += txbytes; | ||
785 | } | ||
786 | if (stat_maxcq > conn->prof.maxcqueue) | ||
787 | conn->prof.maxcqueue = stat_maxcq; | ||
788 | } | ||
723 | } | 789 | } |
724 | 790 | ||
725 | static void | 791 | static void conn_action_connaccept(fsm_instance *fi, int event, void *arg) |
726 | conn_action_connaccept(fsm_instance *fi, int event, void *arg) | ||
727 | { | 792 | { |
728 | struct iucv_event *ev = (struct iucv_event *)arg; | 793 | struct iucv_event *ev = arg; |
729 | struct iucv_connection *conn = ev->conn; | 794 | struct iucv_connection *conn = ev->conn; |
730 | iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data; | 795 | struct iucv_path *path = ev->data; |
731 | struct net_device *netdev = conn->netdev; | 796 | struct net_device *netdev = conn->netdev; |
732 | struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; | 797 | struct netiucv_priv *privptr = netdev_priv(netdev); |
733 | int rc; | 798 | int rc; |
734 | __u16 msglimit; | ||
735 | __u8 udata[16]; | ||
736 | 799 | ||
737 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 800 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
738 | 801 | ||
739 | rc = iucv_accept(eib->ippathid, NETIUCV_QUEUELEN_DEFAULT, udata, 0, | 802 | conn->path = path; |
740 | conn->handle, conn, NULL, &msglimit); | 803 | path->msglim = NETIUCV_QUEUELEN_DEFAULT; |
804 | path->flags = 0; | ||
805 | rc = iucv_path_accept(path, &netiucv_handler, NULL, conn); | ||
741 | if (rc) { | 806 | if (rc) { |
742 | PRINT_WARN("%s: IUCV accept failed with error %d\n", | 807 | PRINT_WARN("%s: IUCV accept failed with error %d\n", |
743 | netdev->name, rc); | 808 | netdev->name, rc); |
@@ -745,183 +810,126 @@ conn_action_connaccept(fsm_instance *fi, int event, void *arg) | |||
745 | return; | 810 | return; |
746 | } | 811 | } |
747 | fsm_newstate(fi, CONN_STATE_IDLE); | 812 | fsm_newstate(fi, CONN_STATE_IDLE); |
748 | conn->pathid = eib->ippathid; | 813 | netdev->tx_queue_len = conn->path->msglim; |
749 | netdev->tx_queue_len = msglimit; | ||
750 | fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev); | 814 | fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev); |
751 | } | 815 | } |
752 | 816 | ||
753 | static void | 817 | static void conn_action_connreject(fsm_instance *fi, int event, void *arg) |
754 | conn_action_connreject(fsm_instance *fi, int event, void *arg) | ||
755 | { | 818 | { |
756 | struct iucv_event *ev = (struct iucv_event *)arg; | 819 | struct iucv_event *ev = arg; |
757 | struct iucv_connection *conn = ev->conn; | 820 | struct iucv_path *path = ev->data; |
758 | struct net_device *netdev = conn->netdev; | ||
759 | iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data; | ||
760 | __u8 udata[16]; | ||
761 | 821 | ||
762 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 822 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
763 | 823 | iucv_path_sever(path, NULL); | |
764 | iucv_sever(eib->ippathid, udata); | ||
765 | if (eib->ippathid != conn->pathid) { | ||
766 | PRINT_INFO("%s: IR Connection Pending; " | ||
767 | "pathid %d does not match original pathid %d\n", | ||
768 | netdev->name, eib->ippathid, conn->pathid); | ||
769 | IUCV_DBF_TEXT_(data, 2, | ||
770 | "connreject: IR pathid %d, conn. pathid %d\n", | ||
771 | eib->ippathid, conn->pathid); | ||
772 | iucv_sever(conn->pathid, udata); | ||
773 | } | ||
774 | } | 824 | } |
775 | 825 | ||
776 | static void | 826 | static void conn_action_connack(fsm_instance *fi, int event, void *arg) |
777 | conn_action_connack(fsm_instance *fi, int event, void *arg) | ||
778 | { | 827 | { |
779 | struct iucv_event *ev = (struct iucv_event *)arg; | 828 | struct iucv_connection *conn = arg; |
780 | struct iucv_connection *conn = ev->conn; | ||
781 | iucv_ConnectionComplete *eib = (iucv_ConnectionComplete *)ev->data; | ||
782 | struct net_device *netdev = conn->netdev; | 829 | struct net_device *netdev = conn->netdev; |
783 | struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; | 830 | struct netiucv_priv *privptr = netdev_priv(netdev); |
784 | 831 | ||
785 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 832 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
786 | |||
787 | fsm_deltimer(&conn->timer); | 833 | fsm_deltimer(&conn->timer); |
788 | fsm_newstate(fi, CONN_STATE_IDLE); | 834 | fsm_newstate(fi, CONN_STATE_IDLE); |
789 | if (eib->ippathid != conn->pathid) { | 835 | netdev->tx_queue_len = conn->path->msglim; |
790 | PRINT_INFO("%s: IR Connection Complete; " | ||
791 | "pathid %d does not match original pathid %d\n", | ||
792 | netdev->name, eib->ippathid, conn->pathid); | ||
793 | IUCV_DBF_TEXT_(data, 2, | ||
794 | "connack: IR pathid %d, conn. pathid %d\n", | ||
795 | eib->ippathid, conn->pathid); | ||
796 | conn->pathid = eib->ippathid; | ||
797 | } | ||
798 | netdev->tx_queue_len = eib->ipmsglim; | ||
799 | fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev); | 836 | fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev); |
800 | } | 837 | } |
801 | 838 | ||
802 | static void | 839 | static void conn_action_conntimsev(fsm_instance *fi, int event, void *arg) |
803 | conn_action_conntimsev(fsm_instance *fi, int event, void *arg) | ||
804 | { | 840 | { |
805 | struct iucv_connection *conn = (struct iucv_connection *)arg; | 841 | struct iucv_connection *conn = arg; |
806 | __u8 udata[16]; | ||
807 | 842 | ||
808 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 843 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
809 | |||
810 | fsm_deltimer(&conn->timer); | 844 | fsm_deltimer(&conn->timer); |
811 | iucv_sever(conn->pathid, udata); | 845 | iucv_path_sever(conn->path, NULL); |
812 | fsm_newstate(fi, CONN_STATE_STARTWAIT); | 846 | fsm_newstate(fi, CONN_STATE_STARTWAIT); |
813 | } | 847 | } |
814 | 848 | ||
815 | static void | 849 | static void conn_action_connsever(fsm_instance *fi, int event, void *arg) |
816 | conn_action_connsever(fsm_instance *fi, int event, void *arg) | ||
817 | { | 850 | { |
818 | struct iucv_event *ev = (struct iucv_event *)arg; | 851 | struct iucv_connection *conn = arg; |
819 | struct iucv_connection *conn = ev->conn; | ||
820 | struct net_device *netdev = conn->netdev; | 852 | struct net_device *netdev = conn->netdev; |
821 | struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; | 853 | struct netiucv_priv *privptr = netdev_priv(netdev); |
822 | __u8 udata[16]; | ||
823 | 854 | ||
824 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 855 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
825 | 856 | ||
826 | fsm_deltimer(&conn->timer); | 857 | fsm_deltimer(&conn->timer); |
827 | iucv_sever(conn->pathid, udata); | 858 | iucv_path_sever(conn->path, NULL); |
828 | PRINT_INFO("%s: Remote dropped connection\n", netdev->name); | 859 | PRINT_INFO("%s: Remote dropped connection\n", netdev->name); |
829 | IUCV_DBF_TEXT(data, 2, | 860 | IUCV_DBF_TEXT(data, 2, |
830 | "conn_action_connsever: Remote dropped connection\n"); | 861 | "conn_action_connsever: Remote dropped connection\n"); |
831 | fsm_newstate(fi, CONN_STATE_STARTWAIT); | 862 | fsm_newstate(fi, CONN_STATE_STARTWAIT); |
832 | fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); | 863 | fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); |
833 | } | 864 | } |
834 | 865 | ||
835 | static void | 866 | static void conn_action_start(fsm_instance *fi, int event, void *arg) |
836 | conn_action_start(fsm_instance *fi, int event, void *arg) | ||
837 | { | 867 | { |
838 | struct iucv_event *ev = (struct iucv_event *)arg; | 868 | struct iucv_connection *conn = arg; |
839 | struct iucv_connection *conn = ev->conn; | ||
840 | __u16 msglimit; | ||
841 | int rc; | 869 | int rc; |
842 | 870 | ||
843 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 871 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
844 | 872 | ||
845 | if (!conn->handle) { | 873 | fsm_newstate(fi, CONN_STATE_STARTWAIT); |
846 | IUCV_DBF_TEXT(trace, 5, "calling iucv_register_program\n"); | ||
847 | conn->handle = | ||
848 | iucv_register_program(iucvMagic, conn->userid, | ||
849 | netiucv_mask, | ||
850 | &netiucv_ops, conn); | ||
851 | fsm_newstate(fi, CONN_STATE_STARTWAIT); | ||
852 | if (!conn->handle) { | ||
853 | fsm_newstate(fi, CONN_STATE_REGERR); | ||
854 | conn->handle = NULL; | ||
855 | IUCV_DBF_TEXT(setup, 2, | ||
856 | "NULL from iucv_register_program\n"); | ||
857 | return; | ||
858 | } | ||
859 | |||
860 | PRINT_DEBUG("%s('%s'): registered successfully\n", | ||
861 | conn->netdev->name, conn->userid); | ||
862 | } | ||
863 | |||
864 | PRINT_DEBUG("%s('%s'): connecting ...\n", | 874 | PRINT_DEBUG("%s('%s'): connecting ...\n", |
865 | conn->netdev->name, conn->userid); | 875 | conn->netdev->name, conn->userid); |
866 | 876 | ||
867 | /* We must set the state before calling iucv_connect because the callback | 877 | /* |
868 | * handler could be called at any point after the connection request is | 878 | * We must set the state before calling iucv_connect because the |
869 | * sent */ | 879 | * callback handler could be called at any point after the connection |
880 | * request is sent | ||
881 | */ | ||
870 | 882 | ||
871 | fsm_newstate(fi, CONN_STATE_SETUPWAIT); | 883 | fsm_newstate(fi, CONN_STATE_SETUPWAIT); |
872 | rc = iucv_connect(&(conn->pathid), NETIUCV_QUEUELEN_DEFAULT, iucvMagic, | 884 | conn->path = iucv_path_alloc(NETIUCV_QUEUELEN_DEFAULT, 0, GFP_KERNEL); |
873 | conn->userid, iucv_host, 0, NULL, &msglimit, | 885 | rc = iucv_path_connect(conn->path, &netiucv_handler, conn->userid, |
874 | conn->handle, conn); | 886 | NULL, iucvMagic, conn); |
875 | switch (rc) { | 887 | switch (rc) { |
876 | case 0: | 888 | case 0: |
877 | conn->netdev->tx_queue_len = msglimit; | 889 | conn->netdev->tx_queue_len = conn->path->msglim; |
878 | fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, | 890 | fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, |
879 | CONN_EVENT_TIMER, conn); | 891 | CONN_EVENT_TIMER, conn); |
880 | return; | 892 | return; |
881 | case 11: | 893 | case 11: |
882 | PRINT_INFO("%s: User %s is currently not available.\n", | 894 | PRINT_INFO("%s: User %s is currently not available.\n", |
883 | conn->netdev->name, | 895 | conn->netdev->name, |
884 | netiucv_printname(conn->userid)); | 896 | netiucv_printname(conn->userid)); |
885 | fsm_newstate(fi, CONN_STATE_STARTWAIT); | 897 | fsm_newstate(fi, CONN_STATE_STARTWAIT); |
886 | return; | 898 | break; |
887 | case 12: | 899 | case 12: |
888 | PRINT_INFO("%s: User %s is currently not ready.\n", | 900 | PRINT_INFO("%s: User %s is currently not ready.\n", |
889 | conn->netdev->name, | 901 | conn->netdev->name, |
890 | netiucv_printname(conn->userid)); | 902 | netiucv_printname(conn->userid)); |
891 | fsm_newstate(fi, CONN_STATE_STARTWAIT); | 903 | fsm_newstate(fi, CONN_STATE_STARTWAIT); |
892 | return; | 904 | break; |
893 | case 13: | 905 | case 13: |
894 | PRINT_WARN("%s: Too many IUCV connections.\n", | 906 | PRINT_WARN("%s: Too many IUCV connections.\n", |
895 | conn->netdev->name); | 907 | conn->netdev->name); |
896 | fsm_newstate(fi, CONN_STATE_CONNERR); | 908 | fsm_newstate(fi, CONN_STATE_CONNERR); |
897 | break; | 909 | break; |
898 | case 14: | 910 | case 14: |
899 | PRINT_WARN( | 911 | PRINT_WARN("%s: User %s has too many IUCV connections.\n", |
900 | "%s: User %s has too many IUCV connections.\n", | 912 | conn->netdev->name, |
901 | conn->netdev->name, | 913 | netiucv_printname(conn->userid)); |
902 | netiucv_printname(conn->userid)); | 914 | fsm_newstate(fi, CONN_STATE_CONNERR); |
903 | fsm_newstate(fi, CONN_STATE_CONNERR); | 915 | break; |
904 | break; | 916 | case 15: |
905 | case 15: | 917 | PRINT_WARN("%s: No IUCV authorization in CP directory.\n", |
906 | PRINT_WARN( | 918 | conn->netdev->name); |
907 | "%s: No IUCV authorization in CP directory.\n", | 919 | fsm_newstate(fi, CONN_STATE_CONNERR); |
908 | conn->netdev->name); | 920 | break; |
909 | fsm_newstate(fi, CONN_STATE_CONNERR); | 921 | default: |
910 | break; | 922 | PRINT_WARN("%s: iucv_connect returned error %d\n", |
911 | default: | 923 | conn->netdev->name, rc); |
912 | PRINT_WARN("%s: iucv_connect returned error %d\n", | 924 | fsm_newstate(fi, CONN_STATE_CONNERR); |
913 | conn->netdev->name, rc); | 925 | break; |
914 | fsm_newstate(fi, CONN_STATE_CONNERR); | ||
915 | break; | ||
916 | } | 926 | } |
917 | IUCV_DBF_TEXT_(setup, 5, "iucv_connect rc is %d\n", rc); | 927 | IUCV_DBF_TEXT_(setup, 5, "iucv_connect rc is %d\n", rc); |
918 | IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n"); | 928 | kfree(conn->path); |
919 | iucv_unregister_program(conn->handle); | 929 | conn->path = NULL; |
920 | conn->handle = NULL; | ||
921 | } | 930 | } |
922 | 931 | ||
923 | static void | 932 | static void netiucv_purge_skb_queue(struct sk_buff_head *q) |
924 | netiucv_purge_skb_queue(struct sk_buff_head *q) | ||
925 | { | 933 | { |
926 | struct sk_buff *skb; | 934 | struct sk_buff *skb; |
927 | 935 | ||
@@ -931,36 +939,34 @@ netiucv_purge_skb_queue(struct sk_buff_head *q) | |||
931 | } | 939 | } |
932 | } | 940 | } |
933 | 941 | ||
934 | static void | 942 | static void conn_action_stop(fsm_instance *fi, int event, void *arg) |
935 | conn_action_stop(fsm_instance *fi, int event, void *arg) | ||
936 | { | 943 | { |
937 | struct iucv_event *ev = (struct iucv_event *)arg; | 944 | struct iucv_event *ev = arg; |
938 | struct iucv_connection *conn = ev->conn; | 945 | struct iucv_connection *conn = ev->conn; |
939 | struct net_device *netdev = conn->netdev; | 946 | struct net_device *netdev = conn->netdev; |
940 | struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; | 947 | struct netiucv_priv *privptr = netdev_priv(netdev); |
941 | 948 | ||
942 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 949 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
943 | 950 | ||
944 | fsm_deltimer(&conn->timer); | 951 | fsm_deltimer(&conn->timer); |
945 | fsm_newstate(fi, CONN_STATE_STOPPED); | 952 | fsm_newstate(fi, CONN_STATE_STOPPED); |
946 | netiucv_purge_skb_queue(&conn->collect_queue); | 953 | netiucv_purge_skb_queue(&conn->collect_queue); |
947 | if (conn->handle) | 954 | if (conn->path) { |
948 | IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n"); | 955 | IUCV_DBF_TEXT(trace, 5, "calling iucv_path_sever\n"); |
949 | iucv_unregister_program(conn->handle); | 956 | iucv_path_sever(conn->path, iucvMagic); |
950 | conn->handle = NULL; | 957 | kfree(conn->path); |
958 | conn->path = NULL; | ||
959 | } | ||
951 | netiucv_purge_skb_queue(&conn->commit_queue); | 960 | netiucv_purge_skb_queue(&conn->commit_queue); |
952 | fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); | 961 | fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); |
953 | } | 962 | } |
954 | 963 | ||
955 | static void | 964 | static void conn_action_inval(fsm_instance *fi, int event, void *arg) |
956 | conn_action_inval(fsm_instance *fi, int event, void *arg) | ||
957 | { | 965 | { |
958 | struct iucv_event *ev = (struct iucv_event *)arg; | 966 | struct iucv_connection *conn = arg; |
959 | struct iucv_connection *conn = ev->conn; | ||
960 | struct net_device *netdev = conn->netdev; | 967 | struct net_device *netdev = conn->netdev; |
961 | 968 | ||
962 | PRINT_WARN("%s: Cannot connect without username\n", | 969 | PRINT_WARN("%s: Cannot connect without username\n", netdev->name); |
963 | netdev->name); | ||
964 | IUCV_DBF_TEXT(data, 2, "conn_action_inval called\n"); | 970 | IUCV_DBF_TEXT(data, 2, "conn_action_inval called\n"); |
965 | } | 971 | } |
966 | 972 | ||
@@ -999,29 +1005,27 @@ static const fsm_node conn_fsm[] = { | |||
999 | static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node); | 1005 | static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node); |
1000 | 1006 | ||
1001 | 1007 | ||
1002 | /** | 1008 | /* |
1003 | * Actions for interface - statemachine. | 1009 | * Actions for interface - statemachine. |
1004 | *****************************************************************************/ | 1010 | */ |
1005 | 1011 | ||
1006 | /** | 1012 | /** |
1007 | * Startup connection by sending CONN_EVENT_START to it. | 1013 | * dev_action_start |
1014 | * @fi: An instance of an interface statemachine. | ||
1015 | * @event: The event, just happened. | ||
1016 | * @arg: Generic pointer, casted from struct net_device * upon call. | ||
1008 | * | 1017 | * |
1009 | * @param fi An instance of an interface statemachine. | 1018 | * Startup connection by sending CONN_EVENT_START to it. |
1010 | * @param event The event, just happened. | ||
1011 | * @param arg Generic pointer, casted from struct net_device * upon call. | ||
1012 | */ | 1019 | */ |
1013 | static void | 1020 | static void dev_action_start(fsm_instance *fi, int event, void *arg) |
1014 | dev_action_start(fsm_instance *fi, int event, void *arg) | ||
1015 | { | 1021 | { |
1016 | struct net_device *dev = (struct net_device *)arg; | 1022 | struct net_device *dev = arg; |
1017 | struct netiucv_priv *privptr = dev->priv; | 1023 | struct netiucv_priv *privptr = netdev_priv(dev); |
1018 | struct iucv_event ev; | ||
1019 | 1024 | ||
1020 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1025 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1021 | 1026 | ||
1022 | ev.conn = privptr->conn; | ||
1023 | fsm_newstate(fi, DEV_STATE_STARTWAIT); | 1027 | fsm_newstate(fi, DEV_STATE_STARTWAIT); |
1024 | fsm_event(privptr->conn->fsm, CONN_EVENT_START, &ev); | 1028 | fsm_event(privptr->conn->fsm, CONN_EVENT_START, privptr->conn); |
1025 | } | 1029 | } |
1026 | 1030 | ||
1027 | /** | 1031 | /** |
@@ -1034,8 +1038,8 @@ dev_action_start(fsm_instance *fi, int event, void *arg) | |||
1034 | static void | 1038 | static void |
1035 | dev_action_stop(fsm_instance *fi, int event, void *arg) | 1039 | dev_action_stop(fsm_instance *fi, int event, void *arg) |
1036 | { | 1040 | { |
1037 | struct net_device *dev = (struct net_device *)arg; | 1041 | struct net_device *dev = arg; |
1038 | struct netiucv_priv *privptr = dev->priv; | 1042 | struct netiucv_priv *privptr = netdev_priv(dev); |
1039 | struct iucv_event ev; | 1043 | struct iucv_event ev; |
1040 | 1044 | ||
1041 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1045 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
@@ -1057,8 +1061,8 @@ dev_action_stop(fsm_instance *fi, int event, void *arg) | |||
1057 | static void | 1061 | static void |
1058 | dev_action_connup(fsm_instance *fi, int event, void *arg) | 1062 | dev_action_connup(fsm_instance *fi, int event, void *arg) |
1059 | { | 1063 | { |
1060 | struct net_device *dev = (struct net_device *)arg; | 1064 | struct net_device *dev = arg; |
1061 | struct netiucv_priv *privptr = dev->priv; | 1065 | struct netiucv_priv *privptr = netdev_priv(dev); |
1062 | 1066 | ||
1063 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1067 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1064 | 1068 | ||
@@ -1131,11 +1135,13 @@ static const int DEV_FSM_LEN = sizeof(dev_fsm) / sizeof(fsm_node); | |||
1131 | * | 1135 | * |
1132 | * @return 0 on success, -ERRNO on failure. (Never fails.) | 1136 | * @return 0 on success, -ERRNO on failure. (Never fails.) |
1133 | */ | 1137 | */ |
1134 | static int | 1138 | static int netiucv_transmit_skb(struct iucv_connection *conn, |
1135 | netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { | 1139 | struct sk_buff *skb) |
1140 | { | ||
1141 | struct iucv_message msg; | ||
1136 | unsigned long saveflags; | 1142 | unsigned long saveflags; |
1137 | ll_header header; | 1143 | struct ll_header header; |
1138 | int rc = 0; | 1144 | int rc; |
1139 | 1145 | ||
1140 | if (fsm_getstate(conn->fsm) != CONN_STATE_IDLE) { | 1146 | if (fsm_getstate(conn->fsm) != CONN_STATE_IDLE) { |
1141 | int l = skb->len + NETIUCV_HDRLEN; | 1147 | int l = skb->len + NETIUCV_HDRLEN; |
@@ -1145,11 +1151,12 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { | |||
1145 | (conn->max_buffsize - NETIUCV_HDRLEN)) { | 1151 | (conn->max_buffsize - NETIUCV_HDRLEN)) { |
1146 | rc = -EBUSY; | 1152 | rc = -EBUSY; |
1147 | IUCV_DBF_TEXT(data, 2, | 1153 | IUCV_DBF_TEXT(data, 2, |
1148 | "EBUSY from netiucv_transmit_skb\n"); | 1154 | "EBUSY from netiucv_transmit_skb\n"); |
1149 | } else { | 1155 | } else { |
1150 | atomic_inc(&skb->users); | 1156 | atomic_inc(&skb->users); |
1151 | skb_queue_tail(&conn->collect_queue, skb); | 1157 | skb_queue_tail(&conn->collect_queue, skb); |
1152 | conn->collect_len += l; | 1158 | conn->collect_len += l; |
1159 | rc = 0; | ||
1153 | } | 1160 | } |
1154 | spin_unlock_irqrestore(&conn->collect_lock, saveflags); | 1161 | spin_unlock_irqrestore(&conn->collect_lock, saveflags); |
1155 | } else { | 1162 | } else { |
@@ -1188,9 +1195,10 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { | |||
1188 | fsm_newstate(conn->fsm, CONN_STATE_TX); | 1195 | fsm_newstate(conn->fsm, CONN_STATE_TX); |
1189 | conn->prof.send_stamp = xtime; | 1196 | conn->prof.send_stamp = xtime; |
1190 | 1197 | ||
1191 | rc = iucv_send(conn->pathid, NULL, 0, 0, 1 /* single_flag */, | 1198 | msg.tag = 1; |
1192 | 0, nskb->data, nskb->len); | 1199 | msg.class = 0; |
1193 | /* Shut up, gcc! nskb is always below 2G. */ | 1200 | rc = iucv_message_send(conn->path, &msg, 0, 0, |
1201 | nskb->data, nskb->len); | ||
1194 | conn->prof.doios_single++; | 1202 | conn->prof.doios_single++; |
1195 | conn->prof.txlen += skb->len; | 1203 | conn->prof.txlen += skb->len; |
1196 | conn->prof.tx_pending++; | 1204 | conn->prof.tx_pending++; |
@@ -1200,7 +1208,7 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { | |||
1200 | struct netiucv_priv *privptr; | 1208 | struct netiucv_priv *privptr; |
1201 | fsm_newstate(conn->fsm, CONN_STATE_IDLE); | 1209 | fsm_newstate(conn->fsm, CONN_STATE_IDLE); |
1202 | conn->prof.tx_pending--; | 1210 | conn->prof.tx_pending--; |
1203 | privptr = (struct netiucv_priv *)conn->netdev->priv; | 1211 | privptr = netdev_priv(conn->netdev); |
1204 | if (privptr) | 1212 | if (privptr) |
1205 | privptr->stats.tx_errors++; | 1213 | privptr->stats.tx_errors++; |
1206 | if (copied) | 1214 | if (copied) |
@@ -1226,9 +1234,9 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { | |||
1226 | return rc; | 1234 | return rc; |
1227 | } | 1235 | } |
1228 | 1236 | ||
1229 | /** | 1237 | /* |
1230 | * Interface API for upper network layers | 1238 | * Interface API for upper network layers |
1231 | *****************************************************************************/ | 1239 | */ |
1232 | 1240 | ||
1233 | /** | 1241 | /** |
1234 | * Open an interface. | 1242 | * Open an interface. |
@@ -1238,9 +1246,11 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { | |||
1238 | * | 1246 | * |
1239 | * @return 0 on success, -ERRNO on failure. (Never fails.) | 1247 | * @return 0 on success, -ERRNO on failure. (Never fails.) |
1240 | */ | 1248 | */ |
1241 | static int | 1249 | static int netiucv_open(struct net_device *dev) |
1242 | netiucv_open(struct net_device *dev) { | 1250 | { |
1243 | fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_START,dev); | 1251 | struct netiucv_priv *priv = netdev_priv(dev); |
1252 | |||
1253 | fsm_event(priv->fsm, DEV_EVENT_START, dev); | ||
1244 | return 0; | 1254 | return 0; |
1245 | } | 1255 | } |
1246 | 1256 | ||
@@ -1252,9 +1262,11 @@ netiucv_open(struct net_device *dev) { | |||
1252 | * | 1262 | * |
1253 | * @return 0 on success, -ERRNO on failure. (Never fails.) | 1263 | * @return 0 on success, -ERRNO on failure. (Never fails.) |
1254 | */ | 1264 | */ |
1255 | static int | 1265 | static int netiucv_close(struct net_device *dev) |
1256 | netiucv_close(struct net_device *dev) { | 1266 | { |
1257 | fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_STOP, dev); | 1267 | struct netiucv_priv *priv = netdev_priv(dev); |
1268 | |||
1269 | fsm_event(priv->fsm, DEV_EVENT_STOP, dev); | ||
1258 | return 0; | 1270 | return 0; |
1259 | } | 1271 | } |
1260 | 1272 | ||
@@ -1271,8 +1283,8 @@ netiucv_close(struct net_device *dev) { | |||
1271 | */ | 1283 | */ |
1272 | static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) | 1284 | static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) |
1273 | { | 1285 | { |
1274 | int rc = 0; | 1286 | struct netiucv_priv *privptr = netdev_priv(dev); |
1275 | struct netiucv_priv *privptr = dev->priv; | 1287 | int rc; |
1276 | 1288 | ||
1277 | IUCV_DBF_TEXT(trace, 4, __FUNCTION__); | 1289 | IUCV_DBF_TEXT(trace, 4, __FUNCTION__); |
1278 | /** | 1290 | /** |
@@ -1312,40 +1324,41 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) | |||
1312 | return -EBUSY; | 1324 | return -EBUSY; |
1313 | } | 1325 | } |
1314 | dev->trans_start = jiffies; | 1326 | dev->trans_start = jiffies; |
1315 | if (netiucv_transmit_skb(privptr->conn, skb)) | 1327 | rc = netiucv_transmit_skb(privptr->conn, skb) != 0; |
1316 | rc = 1; | ||
1317 | netiucv_clear_busy(dev); | 1328 | netiucv_clear_busy(dev); |
1318 | return rc; | 1329 | return rc; |
1319 | } | 1330 | } |
1320 | 1331 | ||
1321 | /** | 1332 | /** |
1322 | * Returns interface statistics of a device. | 1333 | * netiucv_stats |
1334 | * @dev: Pointer to interface struct. | ||
1323 | * | 1335 | * |
1324 | * @param dev Pointer to interface struct. | 1336 | * Returns interface statistics of a device. |
1325 | * | 1337 | * |
1326 | * @return Pointer to stats struct of this interface. | 1338 | * Returns pointer to stats struct of this interface. |
1327 | */ | 1339 | */ |
1328 | static struct net_device_stats * | 1340 | static struct net_device_stats *netiucv_stats (struct net_device * dev) |
1329 | netiucv_stats (struct net_device * dev) | ||
1330 | { | 1341 | { |
1342 | struct netiucv_priv *priv = netdev_priv(dev); | ||
1343 | |||
1331 | IUCV_DBF_TEXT(trace, 5, __FUNCTION__); | 1344 | IUCV_DBF_TEXT(trace, 5, __FUNCTION__); |
1332 | return &((struct netiucv_priv *)dev->priv)->stats; | 1345 | return &priv->stats; |
1333 | } | 1346 | } |
1334 | 1347 | ||
1335 | /** | 1348 | /** |
1336 | * Sets MTU of an interface. | 1349 | * netiucv_change_mtu |
1350 | * @dev: Pointer to interface struct. | ||
1351 | * @new_mtu: The new MTU to use for this interface. | ||
1337 | * | 1352 | * |
1338 | * @param dev Pointer to interface struct. | 1353 | * Sets MTU of an interface. |
1339 | * @param new_mtu The new MTU to use for this interface. | ||
1340 | * | 1354 | * |
1341 | * @return 0 on success, -EINVAL if MTU is out of valid range. | 1355 | * Returns 0 on success, -EINVAL if MTU is out of valid range. |
1342 | * (valid range is 576 .. NETIUCV_MTU_MAX). | 1356 | * (valid range is 576 .. NETIUCV_MTU_MAX). |
1343 | */ | 1357 | */ |
1344 | static int | 1358 | static int netiucv_change_mtu(struct net_device * dev, int new_mtu) |
1345 | netiucv_change_mtu (struct net_device * dev, int new_mtu) | ||
1346 | { | 1359 | { |
1347 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1360 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1348 | if ((new_mtu < 576) || (new_mtu > NETIUCV_MTU_MAX)) { | 1361 | if (new_mtu < 576 || new_mtu > NETIUCV_MTU_MAX) { |
1349 | IUCV_DBF_TEXT(setup, 2, "given MTU out of valid range\n"); | 1362 | IUCV_DBF_TEXT(setup, 2, "given MTU out of valid range\n"); |
1350 | return -EINVAL; | 1363 | return -EINVAL; |
1351 | } | 1364 | } |
@@ -1353,12 +1366,12 @@ netiucv_change_mtu (struct net_device * dev, int new_mtu) | |||
1353 | return 0; | 1366 | return 0; |
1354 | } | 1367 | } |
1355 | 1368 | ||
1356 | /** | 1369 | /* |
1357 | * attributes in sysfs | 1370 | * attributes in sysfs |
1358 | *****************************************************************************/ | 1371 | */ |
1359 | 1372 | ||
1360 | static ssize_t | 1373 | static ssize_t user_show(struct device *dev, struct device_attribute *attr, |
1361 | user_show (struct device *dev, struct device_attribute *attr, char *buf) | 1374 | char *buf) |
1362 | { | 1375 | { |
1363 | struct netiucv_priv *priv = dev->driver_data; | 1376 | struct netiucv_priv *priv = dev->driver_data; |
1364 | 1377 | ||
@@ -1366,8 +1379,8 @@ user_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1366 | return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid)); | 1379 | return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid)); |
1367 | } | 1380 | } |
1368 | 1381 | ||
1369 | static ssize_t | 1382 | static ssize_t user_write(struct device *dev, struct device_attribute *attr, |
1370 | user_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1383 | const char *buf, size_t count) |
1371 | { | 1384 | { |
1372 | struct netiucv_priv *priv = dev->driver_data; | 1385 | struct netiucv_priv *priv = dev->driver_data; |
1373 | struct net_device *ndev = priv->conn->netdev; | 1386 | struct net_device *ndev = priv->conn->netdev; |
@@ -1375,80 +1388,70 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf, | |||
1375 | char *tmp; | 1388 | char *tmp; |
1376 | char username[9]; | 1389 | char username[9]; |
1377 | int i; | 1390 | int i; |
1378 | struct iucv_connection **clist = &iucv_conns.iucv_connections; | 1391 | struct iucv_connection *cp; |
1379 | unsigned long flags; | ||
1380 | 1392 | ||
1381 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1393 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1382 | if (count>9) { | 1394 | if (count > 9) { |
1383 | PRINT_WARN("netiucv: username too long (%d)!\n", (int)count); | 1395 | PRINT_WARN("netiucv: username too long (%d)!\n", (int) count); |
1384 | IUCV_DBF_TEXT_(setup, 2, | 1396 | IUCV_DBF_TEXT_(setup, 2, |
1385 | "%d is length of username\n", (int)count); | 1397 | "%d is length of username\n", (int) count); |
1386 | return -EINVAL; | 1398 | return -EINVAL; |
1387 | } | 1399 | } |
1388 | 1400 | ||
1389 | tmp = strsep((char **) &buf, "\n"); | 1401 | tmp = strsep((char **) &buf, "\n"); |
1390 | for (i=0, p=tmp; i<8 && *p; i++, p++) { | 1402 | for (i = 0, p = tmp; i < 8 && *p; i++, p++) { |
1391 | if (isalnum(*p) || (*p == '$')) | 1403 | if (isalnum(*p) || (*p == '$')) { |
1392 | username[i]= toupper(*p); | 1404 | username[i]= toupper(*p); |
1393 | else if (*p == '\n') { | 1405 | continue; |
1406 | } | ||
1407 | if (*p == '\n') { | ||
1394 | /* trailing lf, grr */ | 1408 | /* trailing lf, grr */ |
1395 | break; | 1409 | break; |
1396 | } else { | ||
1397 | PRINT_WARN("netiucv: Invalid char %c in username!\n", | ||
1398 | *p); | ||
1399 | IUCV_DBF_TEXT_(setup, 2, | ||
1400 | "username: invalid character %c\n", | ||
1401 | *p); | ||
1402 | return -EINVAL; | ||
1403 | } | 1410 | } |
1411 | PRINT_WARN("netiucv: Invalid char %c in username!\n", *p); | ||
1412 | IUCV_DBF_TEXT_(setup, 2, | ||
1413 | "username: invalid character %c\n", *p); | ||
1414 | return -EINVAL; | ||
1404 | } | 1415 | } |
1405 | while (i<8) | 1416 | while (i < 8) |
1406 | username[i++] = ' '; | 1417 | username[i++] = ' '; |
1407 | username[8] = '\0'; | 1418 | username[8] = '\0'; |
1408 | 1419 | ||
1409 | if (memcmp(username, priv->conn->userid, 9)) { | 1420 | if (memcmp(username, priv->conn->userid, 9) && |
1410 | /* username changed */ | 1421 | (ndev->flags & (IFF_UP | IFF_RUNNING))) { |
1411 | if (ndev->flags & (IFF_UP | IFF_RUNNING)) { | 1422 | /* username changed while the interface is active. */ |
1412 | PRINT_WARN( | 1423 | PRINT_WARN("netiucv: device %s active, connected to %s\n", |
1413 | "netiucv: device %s active, connected to %s\n", | 1424 | dev->bus_id, priv->conn->userid); |
1414 | dev->bus_id, priv->conn->userid); | 1425 | PRINT_WARN("netiucv: user cannot be updated\n"); |
1415 | PRINT_WARN("netiucv: user cannot be updated\n"); | 1426 | IUCV_DBF_TEXT(setup, 2, "user_write: device active\n"); |
1416 | IUCV_DBF_TEXT(setup, 2, "user_write: device active\n"); | 1427 | return -EBUSY; |
1417 | return -EBUSY; | 1428 | } |
1429 | read_lock_bh(&iucv_connection_rwlock); | ||
1430 | list_for_each_entry(cp, &iucv_connection_list, list) { | ||
1431 | if (!strncmp(username, cp->userid, 9) && cp->netdev != ndev) { | ||
1432 | read_unlock_bh(&iucv_connection_rwlock); | ||
1433 | PRINT_WARN("netiucv: Connection to %s already " | ||
1434 | "exists\n", username); | ||
1435 | return -EEXIST; | ||
1418 | } | 1436 | } |
1419 | } | 1437 | } |
1420 | read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); | 1438 | read_unlock_bh(&iucv_connection_rwlock); |
1421 | while (*clist) { | ||
1422 | if (!strncmp(username, (*clist)->userid, 9) || | ||
1423 | ((*clist)->netdev != ndev)) | ||
1424 | break; | ||
1425 | clist = &((*clist)->next); | ||
1426 | } | ||
1427 | read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | ||
1428 | if (*clist) { | ||
1429 | PRINT_WARN("netiucv: Connection to %s already exists\n", | ||
1430 | username); | ||
1431 | return -EEXIST; | ||
1432 | } | ||
1433 | memcpy(priv->conn->userid, username, 9); | 1439 | memcpy(priv->conn->userid, username, 9); |
1434 | |||
1435 | return count; | 1440 | return count; |
1436 | |||
1437 | } | 1441 | } |
1438 | 1442 | ||
1439 | static DEVICE_ATTR(user, 0644, user_show, user_write); | 1443 | static DEVICE_ATTR(user, 0644, user_show, user_write); |
1440 | 1444 | ||
1441 | static ssize_t | 1445 | static ssize_t buffer_show (struct device *dev, struct device_attribute *attr, |
1442 | buffer_show (struct device *dev, struct device_attribute *attr, char *buf) | 1446 | char *buf) |
1443 | { | 1447 | { struct netiucv_priv *priv = dev->driver_data; |
1444 | struct netiucv_priv *priv = dev->driver_data; | ||
1445 | 1448 | ||
1446 | IUCV_DBF_TEXT(trace, 5, __FUNCTION__); | 1449 | IUCV_DBF_TEXT(trace, 5, __FUNCTION__); |
1447 | return sprintf(buf, "%d\n", priv->conn->max_buffsize); | 1450 | return sprintf(buf, "%d\n", priv->conn->max_buffsize); |
1448 | } | 1451 | } |
1449 | 1452 | ||
1450 | static ssize_t | 1453 | static ssize_t buffer_write (struct device *dev, struct device_attribute *attr, |
1451 | buffer_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1454 | const char *buf, size_t count) |
1452 | { | 1455 | { |
1453 | struct netiucv_priv *priv = dev->driver_data; | 1456 | struct netiucv_priv *priv = dev->driver_data; |
1454 | struct net_device *ndev = priv->conn->netdev; | 1457 | struct net_device *ndev = priv->conn->netdev; |
@@ -1502,8 +1505,8 @@ buffer_write (struct device *dev, struct device_attribute *attr, const char *buf | |||
1502 | 1505 | ||
1503 | static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write); | 1506 | static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write); |
1504 | 1507 | ||
1505 | static ssize_t | 1508 | static ssize_t dev_fsm_show (struct device *dev, struct device_attribute *attr, |
1506 | dev_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) | 1509 | char *buf) |
1507 | { | 1510 | { |
1508 | struct netiucv_priv *priv = dev->driver_data; | 1511 | struct netiucv_priv *priv = dev->driver_data; |
1509 | 1512 | ||
@@ -1513,8 +1516,8 @@ dev_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1513 | 1516 | ||
1514 | static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL); | 1517 | static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL); |
1515 | 1518 | ||
1516 | static ssize_t | 1519 | static ssize_t conn_fsm_show (struct device *dev, |
1517 | conn_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) | 1520 | struct device_attribute *attr, char *buf) |
1518 | { | 1521 | { |
1519 | struct netiucv_priv *priv = dev->driver_data; | 1522 | struct netiucv_priv *priv = dev->driver_data; |
1520 | 1523 | ||
@@ -1524,8 +1527,8 @@ conn_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1524 | 1527 | ||
1525 | static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL); | 1528 | static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL); |
1526 | 1529 | ||
1527 | static ssize_t | 1530 | static ssize_t maxmulti_show (struct device *dev, |
1528 | maxmulti_show (struct device *dev, struct device_attribute *attr, char *buf) | 1531 | struct device_attribute *attr, char *buf) |
1529 | { | 1532 | { |
1530 | struct netiucv_priv *priv = dev->driver_data; | 1533 | struct netiucv_priv *priv = dev->driver_data; |
1531 | 1534 | ||
@@ -1533,8 +1536,9 @@ maxmulti_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1533 | return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti); | 1536 | return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti); |
1534 | } | 1537 | } |
1535 | 1538 | ||
1536 | static ssize_t | 1539 | static ssize_t maxmulti_write (struct device *dev, |
1537 | maxmulti_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1540 | struct device_attribute *attr, |
1541 | const char *buf, size_t count) | ||
1538 | { | 1542 | { |
1539 | struct netiucv_priv *priv = dev->driver_data; | 1543 | struct netiucv_priv *priv = dev->driver_data; |
1540 | 1544 | ||
@@ -1545,8 +1549,8 @@ maxmulti_write (struct device *dev, struct device_attribute *attr, const char *b | |||
1545 | 1549 | ||
1546 | static DEVICE_ATTR(max_tx_buffer_used, 0644, maxmulti_show, maxmulti_write); | 1550 | static DEVICE_ATTR(max_tx_buffer_used, 0644, maxmulti_show, maxmulti_write); |
1547 | 1551 | ||
1548 | static ssize_t | 1552 | static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr, |
1549 | maxcq_show (struct device *dev, struct device_attribute *attr, char *buf) | 1553 | char *buf) |
1550 | { | 1554 | { |
1551 | struct netiucv_priv *priv = dev->driver_data; | 1555 | struct netiucv_priv *priv = dev->driver_data; |
1552 | 1556 | ||
@@ -1554,8 +1558,8 @@ maxcq_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1554 | return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue); | 1558 | return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue); |
1555 | } | 1559 | } |
1556 | 1560 | ||
1557 | static ssize_t | 1561 | static ssize_t maxcq_write (struct device *dev, struct device_attribute *attr, |
1558 | maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1562 | const char *buf, size_t count) |
1559 | { | 1563 | { |
1560 | struct netiucv_priv *priv = dev->driver_data; | 1564 | struct netiucv_priv *priv = dev->driver_data; |
1561 | 1565 | ||
@@ -1566,8 +1570,8 @@ maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf, | |||
1566 | 1570 | ||
1567 | static DEVICE_ATTR(max_chained_skbs, 0644, maxcq_show, maxcq_write); | 1571 | static DEVICE_ATTR(max_chained_skbs, 0644, maxcq_show, maxcq_write); |
1568 | 1572 | ||
1569 | static ssize_t | 1573 | static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr, |
1570 | sdoio_show (struct device *dev, struct device_attribute *attr, char *buf) | 1574 | char *buf) |
1571 | { | 1575 | { |
1572 | struct netiucv_priv *priv = dev->driver_data; | 1576 | struct netiucv_priv *priv = dev->driver_data; |
1573 | 1577 | ||
@@ -1575,8 +1579,8 @@ sdoio_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1575 | return sprintf(buf, "%ld\n", priv->conn->prof.doios_single); | 1579 | return sprintf(buf, "%ld\n", priv->conn->prof.doios_single); |
1576 | } | 1580 | } |
1577 | 1581 | ||
1578 | static ssize_t | 1582 | static ssize_t sdoio_write (struct device *dev, struct device_attribute *attr, |
1579 | sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1583 | const char *buf, size_t count) |
1580 | { | 1584 | { |
1581 | struct netiucv_priv *priv = dev->driver_data; | 1585 | struct netiucv_priv *priv = dev->driver_data; |
1582 | 1586 | ||
@@ -1587,8 +1591,8 @@ sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, | |||
1587 | 1591 | ||
1588 | static DEVICE_ATTR(tx_single_write_ops, 0644, sdoio_show, sdoio_write); | 1592 | static DEVICE_ATTR(tx_single_write_ops, 0644, sdoio_show, sdoio_write); |
1589 | 1593 | ||
1590 | static ssize_t | 1594 | static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr, |
1591 | mdoio_show (struct device *dev, struct device_attribute *attr, char *buf) | 1595 | char *buf) |
1592 | { | 1596 | { |
1593 | struct netiucv_priv *priv = dev->driver_data; | 1597 | struct netiucv_priv *priv = dev->driver_data; |
1594 | 1598 | ||
@@ -1596,8 +1600,8 @@ mdoio_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1596 | return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi); | 1600 | return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi); |
1597 | } | 1601 | } |
1598 | 1602 | ||
1599 | static ssize_t | 1603 | static ssize_t mdoio_write (struct device *dev, struct device_attribute *attr, |
1600 | mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1604 | const char *buf, size_t count) |
1601 | { | 1605 | { |
1602 | struct netiucv_priv *priv = dev->driver_data; | 1606 | struct netiucv_priv *priv = dev->driver_data; |
1603 | 1607 | ||
@@ -1608,8 +1612,8 @@ mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, | |||
1608 | 1612 | ||
1609 | static DEVICE_ATTR(tx_multi_write_ops, 0644, mdoio_show, mdoio_write); | 1613 | static DEVICE_ATTR(tx_multi_write_ops, 0644, mdoio_show, mdoio_write); |
1610 | 1614 | ||
1611 | static ssize_t | 1615 | static ssize_t txlen_show (struct device *dev, struct device_attribute *attr, |
1612 | txlen_show (struct device *dev, struct device_attribute *attr, char *buf) | 1616 | char *buf) |
1613 | { | 1617 | { |
1614 | struct netiucv_priv *priv = dev->driver_data; | 1618 | struct netiucv_priv *priv = dev->driver_data; |
1615 | 1619 | ||
@@ -1617,8 +1621,8 @@ txlen_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1617 | return sprintf(buf, "%ld\n", priv->conn->prof.txlen); | 1621 | return sprintf(buf, "%ld\n", priv->conn->prof.txlen); |
1618 | } | 1622 | } |
1619 | 1623 | ||
1620 | static ssize_t | 1624 | static ssize_t txlen_write (struct device *dev, struct device_attribute *attr, |
1621 | txlen_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1625 | const char *buf, size_t count) |
1622 | { | 1626 | { |
1623 | struct netiucv_priv *priv = dev->driver_data; | 1627 | struct netiucv_priv *priv = dev->driver_data; |
1624 | 1628 | ||
@@ -1629,8 +1633,8 @@ txlen_write (struct device *dev, struct device_attribute *attr, const char *buf, | |||
1629 | 1633 | ||
1630 | static DEVICE_ATTR(netto_bytes, 0644, txlen_show, txlen_write); | 1634 | static DEVICE_ATTR(netto_bytes, 0644, txlen_show, txlen_write); |
1631 | 1635 | ||
1632 | static ssize_t | 1636 | static ssize_t txtime_show (struct device *dev, struct device_attribute *attr, |
1633 | txtime_show (struct device *dev, struct device_attribute *attr, char *buf) | 1637 | char *buf) |
1634 | { | 1638 | { |
1635 | struct netiucv_priv *priv = dev->driver_data; | 1639 | struct netiucv_priv *priv = dev->driver_data; |
1636 | 1640 | ||
@@ -1638,8 +1642,8 @@ txtime_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1638 | return sprintf(buf, "%ld\n", priv->conn->prof.tx_time); | 1642 | return sprintf(buf, "%ld\n", priv->conn->prof.tx_time); |
1639 | } | 1643 | } |
1640 | 1644 | ||
1641 | static ssize_t | 1645 | static ssize_t txtime_write (struct device *dev, struct device_attribute *attr, |
1642 | txtime_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1646 | const char *buf, size_t count) |
1643 | { | 1647 | { |
1644 | struct netiucv_priv *priv = dev->driver_data; | 1648 | struct netiucv_priv *priv = dev->driver_data; |
1645 | 1649 | ||
@@ -1650,8 +1654,8 @@ txtime_write (struct device *dev, struct device_attribute *attr, const char *buf | |||
1650 | 1654 | ||
1651 | static DEVICE_ATTR(max_tx_io_time, 0644, txtime_show, txtime_write); | 1655 | static DEVICE_ATTR(max_tx_io_time, 0644, txtime_show, txtime_write); |
1652 | 1656 | ||
1653 | static ssize_t | 1657 | static ssize_t txpend_show (struct device *dev, struct device_attribute *attr, |
1654 | txpend_show (struct device *dev, struct device_attribute *attr, char *buf) | 1658 | char *buf) |
1655 | { | 1659 | { |
1656 | struct netiucv_priv *priv = dev->driver_data; | 1660 | struct netiucv_priv *priv = dev->driver_data; |
1657 | 1661 | ||
@@ -1659,8 +1663,8 @@ txpend_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1659 | return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending); | 1663 | return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending); |
1660 | } | 1664 | } |
1661 | 1665 | ||
1662 | static ssize_t | 1666 | static ssize_t txpend_write (struct device *dev, struct device_attribute *attr, |
1663 | txpend_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1667 | const char *buf, size_t count) |
1664 | { | 1668 | { |
1665 | struct netiucv_priv *priv = dev->driver_data; | 1669 | struct netiucv_priv *priv = dev->driver_data; |
1666 | 1670 | ||
@@ -1671,8 +1675,8 @@ txpend_write (struct device *dev, struct device_attribute *attr, const char *buf | |||
1671 | 1675 | ||
1672 | static DEVICE_ATTR(tx_pending, 0644, txpend_show, txpend_write); | 1676 | static DEVICE_ATTR(tx_pending, 0644, txpend_show, txpend_write); |
1673 | 1677 | ||
1674 | static ssize_t | 1678 | static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr, |
1675 | txmpnd_show (struct device *dev, struct device_attribute *attr, char *buf) | 1679 | char *buf) |
1676 | { | 1680 | { |
1677 | struct netiucv_priv *priv = dev->driver_data; | 1681 | struct netiucv_priv *priv = dev->driver_data; |
1678 | 1682 | ||
@@ -1680,8 +1684,8 @@ txmpnd_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1680 | return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending); | 1684 | return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending); |
1681 | } | 1685 | } |
1682 | 1686 | ||
1683 | static ssize_t | 1687 | static ssize_t txmpnd_write (struct device *dev, struct device_attribute *attr, |
1684 | txmpnd_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1688 | const char *buf, size_t count) |
1685 | { | 1689 | { |
1686 | struct netiucv_priv *priv = dev->driver_data; | 1690 | struct netiucv_priv *priv = dev->driver_data; |
1687 | 1691 | ||
@@ -1721,8 +1725,7 @@ static struct attribute_group netiucv_stat_attr_group = { | |||
1721 | .attrs = netiucv_stat_attrs, | 1725 | .attrs = netiucv_stat_attrs, |
1722 | }; | 1726 | }; |
1723 | 1727 | ||
1724 | static inline int | 1728 | static inline int netiucv_add_files(struct device *dev) |
1725 | netiucv_add_files(struct device *dev) | ||
1726 | { | 1729 | { |
1727 | int ret; | 1730 | int ret; |
1728 | 1731 | ||
@@ -1736,18 +1739,16 @@ netiucv_add_files(struct device *dev) | |||
1736 | return ret; | 1739 | return ret; |
1737 | } | 1740 | } |
1738 | 1741 | ||
1739 | static inline void | 1742 | static inline void netiucv_remove_files(struct device *dev) |
1740 | netiucv_remove_files(struct device *dev) | ||
1741 | { | 1743 | { |
1742 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1744 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1743 | sysfs_remove_group(&dev->kobj, &netiucv_stat_attr_group); | 1745 | sysfs_remove_group(&dev->kobj, &netiucv_stat_attr_group); |
1744 | sysfs_remove_group(&dev->kobj, &netiucv_attr_group); | 1746 | sysfs_remove_group(&dev->kobj, &netiucv_attr_group); |
1745 | } | 1747 | } |
1746 | 1748 | ||
1747 | static int | 1749 | static int netiucv_register_device(struct net_device *ndev) |
1748 | netiucv_register_device(struct net_device *ndev) | ||
1749 | { | 1750 | { |
1750 | struct netiucv_priv *priv = ndev->priv; | 1751 | struct netiucv_priv *priv = netdev_priv(ndev); |
1751 | struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); | 1752 | struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); |
1752 | int ret; | 1753 | int ret; |
1753 | 1754 | ||
@@ -1786,8 +1787,7 @@ out_unreg: | |||
1786 | return ret; | 1787 | return ret; |
1787 | } | 1788 | } |
1788 | 1789 | ||
1789 | static void | 1790 | static void netiucv_unregister_device(struct device *dev) |
1790 | netiucv_unregister_device(struct device *dev) | ||
1791 | { | 1791 | { |
1792 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1792 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1793 | netiucv_remove_files(dev); | 1793 | netiucv_remove_files(dev); |
@@ -1798,107 +1798,89 @@ netiucv_unregister_device(struct device *dev) | |||
1798 | * Allocate and initialize a new connection structure. | 1798 | * Allocate and initialize a new connection structure. |
1799 | * Add it to the list of netiucv connections; | 1799 | * Add it to the list of netiucv connections; |
1800 | */ | 1800 | */ |
1801 | static struct iucv_connection * | 1801 | static struct iucv_connection *netiucv_new_connection(struct net_device *dev, |
1802 | netiucv_new_connection(struct net_device *dev, char *username) | 1802 | char *username) |
1803 | { | 1803 | { |
1804 | unsigned long flags; | 1804 | struct iucv_connection *conn; |
1805 | struct iucv_connection **clist = &iucv_conns.iucv_connections; | ||
1806 | struct iucv_connection *conn = | ||
1807 | kzalloc(sizeof(struct iucv_connection), GFP_KERNEL); | ||
1808 | |||
1809 | if (conn) { | ||
1810 | skb_queue_head_init(&conn->collect_queue); | ||
1811 | skb_queue_head_init(&conn->commit_queue); | ||
1812 | spin_lock_init(&conn->collect_lock); | ||
1813 | conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT; | ||
1814 | conn->netdev = dev; | ||
1815 | |||
1816 | conn->rx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT, | ||
1817 | GFP_KERNEL | GFP_DMA); | ||
1818 | if (!conn->rx_buff) { | ||
1819 | kfree(conn); | ||
1820 | return NULL; | ||
1821 | } | ||
1822 | conn->tx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT, | ||
1823 | GFP_KERNEL | GFP_DMA); | ||
1824 | if (!conn->tx_buff) { | ||
1825 | kfree_skb(conn->rx_buff); | ||
1826 | kfree(conn); | ||
1827 | return NULL; | ||
1828 | } | ||
1829 | conn->fsm = init_fsm("netiucvconn", conn_state_names, | ||
1830 | conn_event_names, NR_CONN_STATES, | ||
1831 | NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN, | ||
1832 | GFP_KERNEL); | ||
1833 | if (!conn->fsm) { | ||
1834 | kfree_skb(conn->tx_buff); | ||
1835 | kfree_skb(conn->rx_buff); | ||
1836 | kfree(conn); | ||
1837 | return NULL; | ||
1838 | } | ||
1839 | fsm_settimer(conn->fsm, &conn->timer); | ||
1840 | fsm_newstate(conn->fsm, CONN_STATE_INVALID); | ||
1841 | |||
1842 | if (username) { | ||
1843 | memcpy(conn->userid, username, 9); | ||
1844 | fsm_newstate(conn->fsm, CONN_STATE_STOPPED); | ||
1845 | } | ||
1846 | 1805 | ||
1847 | write_lock_irqsave(&iucv_conns.iucv_rwlock, flags); | 1806 | conn = kzalloc(sizeof(*conn), GFP_KERNEL); |
1848 | conn->next = *clist; | 1807 | if (!conn) |
1849 | *clist = conn; | 1808 | goto out; |
1850 | write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | 1809 | skb_queue_head_init(&conn->collect_queue); |
1810 | skb_queue_head_init(&conn->commit_queue); | ||
1811 | spin_lock_init(&conn->collect_lock); | ||
1812 | conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT; | ||
1813 | conn->netdev = dev; | ||
1814 | |||
1815 | conn->rx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA); | ||
1816 | if (!conn->rx_buff) | ||
1817 | goto out_conn; | ||
1818 | conn->tx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA); | ||
1819 | if (!conn->tx_buff) | ||
1820 | goto out_rx; | ||
1821 | conn->fsm = init_fsm("netiucvconn", conn_state_names, | ||
1822 | conn_event_names, NR_CONN_STATES, | ||
1823 | NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN, | ||
1824 | GFP_KERNEL); | ||
1825 | if (!conn->fsm) | ||
1826 | goto out_tx; | ||
1827 | |||
1828 | fsm_settimer(conn->fsm, &conn->timer); | ||
1829 | fsm_newstate(conn->fsm, CONN_STATE_INVALID); | ||
1830 | |||
1831 | if (username) { | ||
1832 | memcpy(conn->userid, username, 9); | ||
1833 | fsm_newstate(conn->fsm, CONN_STATE_STOPPED); | ||
1851 | } | 1834 | } |
1835 | |||
1836 | write_lock_bh(&iucv_connection_rwlock); | ||
1837 | list_add_tail(&conn->list, &iucv_connection_list); | ||
1838 | write_unlock_bh(&iucv_connection_rwlock); | ||
1852 | return conn; | 1839 | return conn; |
1840 | |||
1841 | out_tx: | ||
1842 | kfree_skb(conn->tx_buff); | ||
1843 | out_rx: | ||
1844 | kfree_skb(conn->rx_buff); | ||
1845 | out_conn: | ||
1846 | kfree(conn); | ||
1847 | out: | ||
1848 | return NULL; | ||
1853 | } | 1849 | } |
1854 | 1850 | ||
1855 | /** | 1851 | /** |
1856 | * Release a connection structure and remove it from the | 1852 | * Release a connection structure and remove it from the |
1857 | * list of netiucv connections. | 1853 | * list of netiucv connections. |
1858 | */ | 1854 | */ |
1859 | static void | 1855 | static void netiucv_remove_connection(struct iucv_connection *conn) |
1860 | netiucv_remove_connection(struct iucv_connection *conn) | ||
1861 | { | 1856 | { |
1862 | struct iucv_connection **clist = &iucv_conns.iucv_connections; | ||
1863 | unsigned long flags; | ||
1864 | |||
1865 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1857 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1866 | if (conn == NULL) | 1858 | write_lock_bh(&iucv_connection_rwlock); |
1867 | return; | 1859 | list_del_init(&conn->list); |
1868 | write_lock_irqsave(&iucv_conns.iucv_rwlock, flags); | 1860 | write_unlock_bh(&iucv_connection_rwlock); |
1869 | while (*clist) { | 1861 | if (conn->path) { |
1870 | if (*clist == conn) { | 1862 | iucv_path_sever(conn->path, iucvMagic); |
1871 | *clist = conn->next; | 1863 | kfree(conn->path); |
1872 | write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | 1864 | conn->path = NULL; |
1873 | if (conn->handle) { | ||
1874 | iucv_unregister_program(conn->handle); | ||
1875 | conn->handle = NULL; | ||
1876 | } | ||
1877 | fsm_deltimer(&conn->timer); | ||
1878 | kfree_fsm(conn->fsm); | ||
1879 | kfree_skb(conn->rx_buff); | ||
1880 | kfree_skb(conn->tx_buff); | ||
1881 | return; | ||
1882 | } | ||
1883 | clist = &((*clist)->next); | ||
1884 | } | 1865 | } |
1885 | write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | 1866 | fsm_deltimer(&conn->timer); |
1867 | kfree_fsm(conn->fsm); | ||
1868 | kfree_skb(conn->rx_buff); | ||
1869 | kfree_skb(conn->tx_buff); | ||
1886 | } | 1870 | } |
1887 | 1871 | ||
1888 | /** | 1872 | /** |
1889 | * Release everything of a net device. | 1873 | * Release everything of a net device. |
1890 | */ | 1874 | */ |
1891 | static void | 1875 | static void netiucv_free_netdevice(struct net_device *dev) |
1892 | netiucv_free_netdevice(struct net_device *dev) | ||
1893 | { | 1876 | { |
1894 | struct netiucv_priv *privptr; | 1877 | struct netiucv_priv *privptr = netdev_priv(dev); |
1895 | 1878 | ||
1896 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1879 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1897 | 1880 | ||
1898 | if (!dev) | 1881 | if (!dev) |
1899 | return; | 1882 | return; |
1900 | 1883 | ||
1901 | privptr = (struct netiucv_priv *)dev->priv; | ||
1902 | if (privptr) { | 1884 | if (privptr) { |
1903 | if (privptr->conn) | 1885 | if (privptr->conn) |
1904 | netiucv_remove_connection(privptr->conn); | 1886 | netiucv_remove_connection(privptr->conn); |
@@ -1913,11 +1895,8 @@ netiucv_free_netdevice(struct net_device *dev) | |||
1913 | /** | 1895 | /** |
1914 | * Initialize a net device. (Called from kernel in alloc_netdev()) | 1896 | * Initialize a net device. (Called from kernel in alloc_netdev()) |
1915 | */ | 1897 | */ |
1916 | static void | 1898 | static void netiucv_setup_netdevice(struct net_device *dev) |
1917 | netiucv_setup_netdevice(struct net_device *dev) | ||
1918 | { | 1899 | { |
1919 | memset(dev->priv, 0, sizeof(struct netiucv_priv)); | ||
1920 | |||
1921 | dev->mtu = NETIUCV_MTU_DEFAULT; | 1900 | dev->mtu = NETIUCV_MTU_DEFAULT; |
1922 | dev->hard_start_xmit = netiucv_tx; | 1901 | dev->hard_start_xmit = netiucv_tx; |
1923 | dev->open = netiucv_open; | 1902 | dev->open = netiucv_open; |
@@ -1936,8 +1915,7 @@ netiucv_setup_netdevice(struct net_device *dev) | |||
1936 | /** | 1915 | /** |
1937 | * Allocate and initialize everything of a net device. | 1916 | * Allocate and initialize everything of a net device. |
1938 | */ | 1917 | */ |
1939 | static struct net_device * | 1918 | static struct net_device *netiucv_init_netdevice(char *username) |
1940 | netiucv_init_netdevice(char *username) | ||
1941 | { | 1919 | { |
1942 | struct netiucv_priv *privptr; | 1920 | struct netiucv_priv *privptr; |
1943 | struct net_device *dev; | 1921 | struct net_device *dev; |
@@ -1946,40 +1924,40 @@ netiucv_init_netdevice(char *username) | |||
1946 | netiucv_setup_netdevice); | 1924 | netiucv_setup_netdevice); |
1947 | if (!dev) | 1925 | if (!dev) |
1948 | return NULL; | 1926 | return NULL; |
1949 | if (dev_alloc_name(dev, dev->name) < 0) { | 1927 | if (dev_alloc_name(dev, dev->name) < 0) |
1950 | free_netdev(dev); | 1928 | goto out_netdev; |
1951 | return NULL; | ||
1952 | } | ||
1953 | 1929 | ||
1954 | privptr = (struct netiucv_priv *)dev->priv; | 1930 | privptr = netdev_priv(dev); |
1955 | privptr->fsm = init_fsm("netiucvdev", dev_state_names, | 1931 | privptr->fsm = init_fsm("netiucvdev", dev_state_names, |
1956 | dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS, | 1932 | dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS, |
1957 | dev_fsm, DEV_FSM_LEN, GFP_KERNEL); | 1933 | dev_fsm, DEV_FSM_LEN, GFP_KERNEL); |
1958 | if (!privptr->fsm) { | 1934 | if (!privptr->fsm) |
1959 | free_netdev(dev); | 1935 | goto out_netdev; |
1960 | return NULL; | 1936 | |
1961 | } | ||
1962 | privptr->conn = netiucv_new_connection(dev, username); | 1937 | privptr->conn = netiucv_new_connection(dev, username); |
1963 | if (!privptr->conn) { | 1938 | if (!privptr->conn) { |
1964 | kfree_fsm(privptr->fsm); | ||
1965 | free_netdev(dev); | ||
1966 | IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_new_connection\n"); | 1939 | IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_new_connection\n"); |
1967 | return NULL; | 1940 | goto out_fsm; |
1968 | } | 1941 | } |
1969 | fsm_newstate(privptr->fsm, DEV_STATE_STOPPED); | 1942 | fsm_newstate(privptr->fsm, DEV_STATE_STOPPED); |
1970 | |||
1971 | return dev; | 1943 | return dev; |
1944 | |||
1945 | out_fsm: | ||
1946 | kfree_fsm(privptr->fsm); | ||
1947 | out_netdev: | ||
1948 | free_netdev(dev); | ||
1949 | return NULL; | ||
1972 | } | 1950 | } |
1973 | 1951 | ||
1974 | static ssize_t | 1952 | static ssize_t conn_write(struct device_driver *drv, |
1975 | conn_write(struct device_driver *drv, const char *buf, size_t count) | 1953 | const char *buf, size_t count) |
1976 | { | 1954 | { |
1977 | char *p; | 1955 | const char *p; |
1978 | char username[9]; | 1956 | char username[9]; |
1979 | int i, ret; | 1957 | int i, rc; |
1980 | struct net_device *dev; | 1958 | struct net_device *dev; |
1981 | struct iucv_connection **clist = &iucv_conns.iucv_connections; | 1959 | struct netiucv_priv *priv; |
1982 | unsigned long flags; | 1960 | struct iucv_connection *cp; |
1983 | 1961 | ||
1984 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1962 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1985 | if (count>9) { | 1963 | if (count>9) { |
@@ -1988,83 +1966,82 @@ conn_write(struct device_driver *drv, const char *buf, size_t count) | |||
1988 | return -EINVAL; | 1966 | return -EINVAL; |
1989 | } | 1967 | } |
1990 | 1968 | ||
1991 | for (i=0, p=(char *)buf; i<8 && *p; i++, p++) { | 1969 | for (i = 0, p = buf; i < 8 && *p; i++, p++) { |
1992 | if (isalnum(*p) || (*p == '$')) | 1970 | if (isalnum(*p) || *p == '$') { |
1993 | username[i]= toupper(*p); | 1971 | username[i] = toupper(*p); |
1994 | else if (*p == '\n') { | 1972 | continue; |
1973 | } | ||
1974 | if (*p == '\n') | ||
1995 | /* trailing lf, grr */ | 1975 | /* trailing lf, grr */ |
1996 | break; | 1976 | break; |
1997 | } else { | 1977 | PRINT_WARN("netiucv: Invalid character in username!\n"); |
1998 | PRINT_WARN("netiucv: Invalid character in username!\n"); | 1978 | IUCV_DBF_TEXT_(setup, 2, |
1999 | IUCV_DBF_TEXT_(setup, 2, | 1979 | "conn_write: invalid character %c\n", *p); |
2000 | "conn_write: invalid character %c\n", *p); | 1980 | return -EINVAL; |
2001 | return -EINVAL; | ||
2002 | } | ||
2003 | } | 1981 | } |
2004 | while (i<8) | 1982 | while (i < 8) |
2005 | username[i++] = ' '; | 1983 | username[i++] = ' '; |
2006 | username[8] = '\0'; | 1984 | username[8] = '\0'; |
2007 | 1985 | ||
2008 | read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); | 1986 | read_lock_bh(&iucv_connection_rwlock); |
2009 | while (*clist) { | 1987 | list_for_each_entry(cp, &iucv_connection_list, list) { |
2010 | if (!strncmp(username, (*clist)->userid, 9)) | 1988 | if (!strncmp(username, cp->userid, 9)) { |
2011 | break; | 1989 | read_unlock_bh(&iucv_connection_rwlock); |
2012 | clist = &((*clist)->next); | 1990 | PRINT_WARN("netiucv: Connection to %s already " |
2013 | } | 1991 | "exists\n", username); |
2014 | read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | 1992 | return -EEXIST; |
2015 | if (*clist) { | 1993 | } |
2016 | PRINT_WARN("netiucv: Connection to %s already exists\n", | ||
2017 | username); | ||
2018 | return -EEXIST; | ||
2019 | } | 1994 | } |
1995 | read_unlock_bh(&iucv_connection_rwlock); | ||
1996 | |||
2020 | dev = netiucv_init_netdevice(username); | 1997 | dev = netiucv_init_netdevice(username); |
2021 | if (!dev) { | 1998 | if (!dev) { |
2022 | PRINT_WARN( | 1999 | PRINT_WARN("netiucv: Could not allocate network device " |
2023 | "netiucv: Could not allocate network device structure " | 2000 | "structure for user '%s'\n", |
2024 | "for user '%s'\n", netiucv_printname(username)); | 2001 | netiucv_printname(username)); |
2025 | IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n"); | 2002 | IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n"); |
2026 | return -ENODEV; | 2003 | return -ENODEV; |
2027 | } | 2004 | } |
2028 | 2005 | ||
2029 | if ((ret = netiucv_register_device(dev))) { | 2006 | rc = netiucv_register_device(dev); |
2007 | if (rc) { | ||
2030 | IUCV_DBF_TEXT_(setup, 2, | 2008 | IUCV_DBF_TEXT_(setup, 2, |
2031 | "ret %d from netiucv_register_device\n", ret); | 2009 | "ret %d from netiucv_register_device\n", rc); |
2032 | goto out_free_ndev; | 2010 | goto out_free_ndev; |
2033 | } | 2011 | } |
2034 | 2012 | ||
2035 | /* sysfs magic */ | 2013 | /* sysfs magic */ |
2036 | SET_NETDEV_DEV(dev, | 2014 | priv = netdev_priv(dev); |
2037 | (struct device*)((struct netiucv_priv*)dev->priv)->dev); | 2015 | SET_NETDEV_DEV(dev, priv->dev); |
2038 | 2016 | ||
2039 | if ((ret = register_netdev(dev))) { | 2017 | rc = register_netdev(dev); |
2040 | netiucv_unregister_device((struct device*) | 2018 | if (rc) |
2041 | ((struct netiucv_priv*)dev->priv)->dev); | 2019 | goto out_unreg; |
2042 | goto out_free_ndev; | ||
2043 | } | ||
2044 | 2020 | ||
2045 | PRINT_INFO("%s: '%s'\n", dev->name, netiucv_printname(username)); | 2021 | PRINT_INFO("%s: '%s'\n", dev->name, netiucv_printname(username)); |
2046 | 2022 | ||
2047 | return count; | 2023 | return count; |
2048 | 2024 | ||
2025 | out_unreg: | ||
2026 | netiucv_unregister_device(priv->dev); | ||
2049 | out_free_ndev: | 2027 | out_free_ndev: |
2050 | PRINT_WARN("netiucv: Could not register '%s'\n", dev->name); | 2028 | PRINT_WARN("netiucv: Could not register '%s'\n", dev->name); |
2051 | IUCV_DBF_TEXT(setup, 2, "conn_write: could not register\n"); | 2029 | IUCV_DBF_TEXT(setup, 2, "conn_write: could not register\n"); |
2052 | netiucv_free_netdevice(dev); | 2030 | netiucv_free_netdevice(dev); |
2053 | return ret; | 2031 | return rc; |
2054 | } | 2032 | } |
2055 | 2033 | ||
2056 | static DRIVER_ATTR(connection, 0200, NULL, conn_write); | 2034 | static DRIVER_ATTR(connection, 0200, NULL, conn_write); |
2057 | 2035 | ||
2058 | static ssize_t | 2036 | static ssize_t remove_write (struct device_driver *drv, |
2059 | remove_write (struct device_driver *drv, const char *buf, size_t count) | 2037 | const char *buf, size_t count) |
2060 | { | 2038 | { |
2061 | struct iucv_connection **clist = &iucv_conns.iucv_connections; | 2039 | struct iucv_connection *cp; |
2062 | unsigned long flags; | ||
2063 | struct net_device *ndev; | 2040 | struct net_device *ndev; |
2064 | struct netiucv_priv *priv; | 2041 | struct netiucv_priv *priv; |
2065 | struct device *dev; | 2042 | struct device *dev; |
2066 | char name[IFNAMSIZ]; | 2043 | char name[IFNAMSIZ]; |
2067 | char *p; | 2044 | const char *p; |
2068 | int i; | 2045 | int i; |
2069 | 2046 | ||
2070 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 2047 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
@@ -2072,33 +2049,27 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) | |||
2072 | if (count >= IFNAMSIZ) | 2049 | if (count >= IFNAMSIZ) |
2073 | count = IFNAMSIZ - 1;; | 2050 | count = IFNAMSIZ - 1;; |
2074 | 2051 | ||
2075 | for (i=0, p=(char *)buf; i<count && *p; i++, p++) { | 2052 | for (i = 0, p = buf; i < count && *p; i++, p++) { |
2076 | if ((*p == '\n') || (*p == ' ')) { | 2053 | if (*p == '\n' || *p == ' ') |
2077 | /* trailing lf, grr */ | 2054 | /* trailing lf, grr */ |
2078 | break; | 2055 | break; |
2079 | } else { | 2056 | name[i] = *p; |
2080 | name[i]=*p; | ||
2081 | } | ||
2082 | } | 2057 | } |
2083 | name[i] = '\0'; | 2058 | name[i] = '\0'; |
2084 | 2059 | ||
2085 | read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); | 2060 | read_lock_bh(&iucv_connection_rwlock); |
2086 | while (*clist) { | 2061 | list_for_each_entry(cp, &iucv_connection_list, list) { |
2087 | ndev = (*clist)->netdev; | 2062 | ndev = cp->netdev; |
2088 | priv = (struct netiucv_priv*)ndev->priv; | 2063 | priv = netdev_priv(ndev); |
2089 | dev = priv->dev; | 2064 | dev = priv->dev; |
2090 | 2065 | if (strncmp(name, ndev->name, count)) | |
2091 | if (strncmp(name, ndev->name, count)) { | 2066 | continue; |
2092 | clist = &((*clist)->next); | 2067 | read_unlock_bh(&iucv_connection_rwlock); |
2093 | continue; | ||
2094 | } | ||
2095 | read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | ||
2096 | if (ndev->flags & (IFF_UP | IFF_RUNNING)) { | 2068 | if (ndev->flags & (IFF_UP | IFF_RUNNING)) { |
2097 | PRINT_WARN( | 2069 | PRINT_WARN("netiucv: net device %s active with peer " |
2098 | "netiucv: net device %s active with peer %s\n", | 2070 | "%s\n", ndev->name, priv->conn->userid); |
2099 | ndev->name, priv->conn->userid); | ||
2100 | PRINT_WARN("netiucv: %s cannot be removed\n", | 2071 | PRINT_WARN("netiucv: %s cannot be removed\n", |
2101 | ndev->name); | 2072 | ndev->name); |
2102 | IUCV_DBF_TEXT(data, 2, "remove_write: still active\n"); | 2073 | IUCV_DBF_TEXT(data, 2, "remove_write: still active\n"); |
2103 | return -EBUSY; | 2074 | return -EBUSY; |
2104 | } | 2075 | } |
@@ -2106,7 +2077,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) | |||
2106 | netiucv_unregister_device(dev); | 2077 | netiucv_unregister_device(dev); |
2107 | return count; | 2078 | return count; |
2108 | } | 2079 | } |
2109 | read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | 2080 | read_unlock_bh(&iucv_connection_rwlock); |
2110 | PRINT_WARN("netiucv: net device %s unknown\n", name); | 2081 | PRINT_WARN("netiucv: net device %s unknown\n", name); |
2111 | IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n"); | 2082 | IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n"); |
2112 | return -EINVAL; | 2083 | return -EINVAL; |
@@ -2114,67 +2085,86 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) | |||
2114 | 2085 | ||
2115 | static DRIVER_ATTR(remove, 0200, NULL, remove_write); | 2086 | static DRIVER_ATTR(remove, 0200, NULL, remove_write); |
2116 | 2087 | ||
2117 | static void | 2088 | static struct attribute * netiucv_drv_attrs[] = { |
2118 | netiucv_banner(void) | 2089 | &driver_attr_connection.attr, |
2090 | &driver_attr_remove.attr, | ||
2091 | NULL, | ||
2092 | }; | ||
2093 | |||
2094 | static struct attribute_group netiucv_drv_attr_group = { | ||
2095 | .attrs = netiucv_drv_attrs, | ||
2096 | }; | ||
2097 | |||
2098 | static void netiucv_banner(void) | ||
2119 | { | 2099 | { |
2120 | PRINT_INFO("NETIUCV driver initialized\n"); | 2100 | PRINT_INFO("NETIUCV driver initialized\n"); |
2121 | } | 2101 | } |
2122 | 2102 | ||
2123 | static void __exit | 2103 | static void __exit netiucv_exit(void) |
2124 | netiucv_exit(void) | ||
2125 | { | 2104 | { |
2105 | struct iucv_connection *cp; | ||
2106 | struct net_device *ndev; | ||
2107 | struct netiucv_priv *priv; | ||
2108 | struct device *dev; | ||
2109 | |||
2126 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 2110 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
2127 | while (iucv_conns.iucv_connections) { | 2111 | while (!list_empty(&iucv_connection_list)) { |
2128 | struct net_device *ndev = iucv_conns.iucv_connections->netdev; | 2112 | cp = list_entry(iucv_connection_list.next, |
2129 | struct netiucv_priv *priv = (struct netiucv_priv*)ndev->priv; | 2113 | struct iucv_connection, list); |
2130 | struct device *dev = priv->dev; | 2114 | list_del(&cp->list); |
2115 | ndev = cp->netdev; | ||
2116 | priv = netdev_priv(ndev); | ||
2117 | dev = priv->dev; | ||
2131 | 2118 | ||
2132 | unregister_netdev(ndev); | 2119 | unregister_netdev(ndev); |
2133 | netiucv_unregister_device(dev); | 2120 | netiucv_unregister_device(dev); |
2134 | } | 2121 | } |
2135 | 2122 | ||
2136 | driver_remove_file(&netiucv_driver, &driver_attr_connection); | 2123 | sysfs_remove_group(&netiucv_driver.kobj, &netiucv_drv_attr_group); |
2137 | driver_remove_file(&netiucv_driver, &driver_attr_remove); | ||
2138 | driver_unregister(&netiucv_driver); | 2124 | driver_unregister(&netiucv_driver); |
2125 | iucv_unregister(&netiucv_handler, 1); | ||
2139 | iucv_unregister_dbf_views(); | 2126 | iucv_unregister_dbf_views(); |
2140 | 2127 | ||
2141 | PRINT_INFO("NETIUCV driver unloaded\n"); | 2128 | PRINT_INFO("NETIUCV driver unloaded\n"); |
2142 | return; | 2129 | return; |
2143 | } | 2130 | } |
2144 | 2131 | ||
2145 | static int __init | 2132 | static int __init netiucv_init(void) |
2146 | netiucv_init(void) | ||
2147 | { | 2133 | { |
2148 | int ret; | 2134 | int rc; |
2149 | 2135 | ||
2150 | ret = iucv_register_dbf_views(); | 2136 | rc = iucv_register_dbf_views(); |
2151 | if (ret) { | 2137 | if (rc) |
2152 | PRINT_WARN("netiucv_init failed, " | 2138 | goto out; |
2153 | "iucv_register_dbf_views rc = %d\n", ret); | 2139 | rc = iucv_register(&netiucv_handler, 1); |
2154 | return ret; | 2140 | if (rc) |
2155 | } | 2141 | goto out_dbf; |
2156 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 2142 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
2157 | ret = driver_register(&netiucv_driver); | 2143 | rc = driver_register(&netiucv_driver); |
2158 | if (ret) { | 2144 | if (rc) { |
2159 | PRINT_ERR("NETIUCV: failed to register driver.\n"); | 2145 | PRINT_ERR("NETIUCV: failed to register driver.\n"); |
2160 | IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", ret); | 2146 | IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc); |
2161 | iucv_unregister_dbf_views(); | 2147 | goto out_iucv; |
2162 | return ret; | ||
2163 | } | 2148 | } |
2164 | 2149 | ||
2165 | /* Add entry for specifying connections. */ | 2150 | rc = sysfs_create_group(&netiucv_driver.kobj, &netiucv_drv_attr_group); |
2166 | ret = driver_create_file(&netiucv_driver, &driver_attr_connection); | 2151 | if (rc) { |
2167 | if (!ret) { | 2152 | PRINT_ERR("NETIUCV: failed to add driver attributes.\n"); |
2168 | ret = driver_create_file(&netiucv_driver, &driver_attr_remove); | 2153 | IUCV_DBF_TEXT_(setup, 2, |
2169 | netiucv_banner(); | 2154 | "ret %d - netiucv_drv_attr_group\n", rc); |
2170 | rwlock_init(&iucv_conns.iucv_rwlock); | 2155 | goto out_driver; |
2171 | } else { | ||
2172 | PRINT_ERR("NETIUCV: failed to add driver attribute.\n"); | ||
2173 | IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_create_file\n", ret); | ||
2174 | driver_unregister(&netiucv_driver); | ||
2175 | iucv_unregister_dbf_views(); | ||
2176 | } | 2156 | } |
2177 | return ret; | 2157 | netiucv_banner(); |
2158 | return rc; | ||
2159 | |||
2160 | out_driver: | ||
2161 | driver_unregister(&netiucv_driver); | ||
2162 | out_iucv: | ||
2163 | iucv_unregister(&netiucv_handler, 1); | ||
2164 | out_dbf: | ||
2165 | iucv_unregister_dbf_views(); | ||
2166 | out: | ||
2167 | return rc; | ||
2178 | } | 2168 | } |
2179 | 2169 | ||
2180 | module_init(netiucv_init); | 2170 | module_init(netiucv_init); |